143行js顶部进度条最小插件-nanobar.js源码解析

网页顶部进度条插件的有四五种,基本原理就是动态地创建一个元素,然后通过设置它的width来实现动画效果,width增长到达指定位置时,将其去掉。
来看看nanobar.js作者jacoborus是怎么做到的吧!

/* http://nanobar.micronube.com/  ||  https://github.com/jacoborus/nanobar/    MIT LICENSE */
(function (root) {
  ‘use strict‘
  // container styles
  var css = ‘.nanobar{width:100%;height:4px;z-index:9999;top:0}.bar{width:0;height:100%;transition:height .3s;background:#000}‘

  // add required css in head div
  function addCss () {
    var s = document.getElementById(‘nanobarcss‘)

    // check whether style tag is already inserted
    if (s === null) {
      s = document.createElement(‘style‘)
      s.type = ‘text/css‘
      s.id = ‘nanobarcss‘
      document.head.insertBefore(s, document.head.firstChild)
      // the world
      if (!s.styleSheet) return s.appendChild(document.createTextNode(css))
      // IE
      s.styleSheet.cssText = css
    }
  }

  function addClass (el, cls) {
    if (el.classList) el.classList.add(cls)
    else el.className += ‘ ‘ + cls
  }

  // create a progress bar
  // this will be destroyed after reaching 100% progress
  function createBar (rm) {
    // create progress element
    var el = document.createElement(‘div‘),
        width = 0,
        here = 0,
        on = 0,
        bar = {
          el: el,
          go: go
        }

    addClass(el, ‘bar‘)

    // animation loop
    function move () {
      var dist = width - here

      if (dist < 0.1 && dist > -0.1) {
        place(here)
        on = 0
        if (width === 100) {
          el.style.height = 0
          setTimeout(function () {
            rm(el)
          }, 300)
        }
      } else {
        place(width - dist / 4)
        setTimeout(go, 16)
      }
    }

    // set bar width
    function place (num) {
      width = num
      el.style.width = width + ‘%‘
    }

    function go (num) {
      if (num >= 0) {
        here = num
        if (!on) {
          on = 1
          move()
        }
      } else if (on) {
        move()
      }
    }
    return bar
  }

  function Nanobar (opts) {
    opts = opts || {}
    // set options
    var el = document.createElement(‘div‘),
        applyGo,
        nanobar = {
          el: el,
          go: function (p) {
            // expand bar
            applyGo(p)
            // create new bar when progress reaches 100%
            if (p === 100) {
              init()
            }
          }
        }

    // remove element from nanobar container
    function rm (child) {
      el.removeChild(child)
    }

    // create and insert progress var in nanobar container
    function init () {
      var bar = createBar(rm)
      el.appendChild(bar.el)
      applyGo = bar.go
    }

    addCss()

    addClass(el, ‘nanobar‘)
    if (opts.id) el.id = opts.id
    if (opts.classname) addClass(el, opts.classname)

    // insert container
    if (opts.target) {
      // inside a div
      el.style.position = ‘relative‘
      opts.target.insertBefore(el, opts.target.firstChild)
    } else {
      // on top of the page
      el.style.position = ‘fixed‘
      document.getElementsByTagName(‘body‘)[0].appendChild(el)
    }

    init()
    return nanobar
  }

  if (typeof exports === ‘object‘) {
    // CommonJS
    module.exports = Nanobar
  } else if (typeof define === ‘function‘ && define.amd) {
    // AMD. Register as an anonymous module.
    define([], function () { return Nanobar })
  } else {
    // Browser globals
    root.Nanobar = Nanobar
  }
}(this))


大体看下来,这个插件有这样几个特点:

  • dom+js原生选择器
  • 支持模块化
  • es5+IIFE
  • 不用分号派

详细来看:

在程序的开头,定义了必要的Css属性,包括bar(主体)和Nanobar(容器)两个class:

.nanobar{
width:100%;
height:4px;
z-index:9999;
top:0
}

.bar{
width:0;
height:100%;
transition:height .3s;
background:#000
}

从css内容来看,仅有.bar有transition:height .3s的过渡设置,height过渡发生的时间应该是被删除时。在横向应该是没有动画效果,但是从官网演示效果来看,横向仍然有一定的动画效果,这个问题下面会提到。

构造函数NanoBar

NanoBar接受一个opts作为参数,文档记载的opts详细内容如下:

名称 功能
id 指定nanobar的id
classname 指定nanobar的class
target 指定Nanobar的表示位置,一般对于做顶部进度条来说不到。值得一提的是,这个参数类型为DOM Element,你必须使用document.getxxxxx之类的方法为其赋值。

首先声明了三个变量:

名称 描述
el 这就是动态创建的元素-一个既没有ID也没有Class的空div
applyGo 进度条移动的方法
nanobar nanobar对象,它将在new构造函数时作为结果返回

其中,nanobar包含这两个元素:

名称 描述
el 上面动态创建的元素
go 对外开放的方法,参数为数值,那么它肯定代表了百分比而不是像素等实际物理单位

此处的go处理内实质上调用的是applyGo,而applyGo此时肯定为undefined,所以applyGo实际上在别处赋值。这样处理的结果,相当于是一层封装,隐藏了内部实际的go方法内容。

另外也可以得出nanobar的最简单的使用方法:

var nanobar = new Nanobar();
nanobar.go(80);

接下来,声明了两个内部函数,这两个内部函数可以访问上面提到的三个变量:

名称 作用
rm 用于进度完成后,删除动态创建的元素
init 初始化方法,这个需要重点关注

然后是一些必要处理,由这三个部分组成:

  1. addCss方法,为head节点内增加&lt;style id="nanobarcss"&gt;节点,并把上文的css填入其中。
  2. 调用addClass方法,创建类名为nanobar的容器。需要注意的是,相比于直接操作className方法内调用了HTML5的新APIclassList,使用它可以像jquery的addClass、removeClass一样方便的对dom对象的class进行增加删除判断。更多信息请看这里
  3. 接下来是对opts参数进行处理:
    主要是为el元素赋予id和className,根据是否指定了父容器,也就是target,改变容器的position,并且最终将它插入到对应的位置上。

接着来看init()方法:

前面所有的操作,创建了一个名为nanobar的容器,接下来就该创建bar主体了。

可以看到,bar变量内仍然和nanobar一样,由elgo两部分组成,go最终将被赋值到外层容器的applyGoel将被作为子元素插入到外层容器的el内。

这样,当用最简单的方式调用go时,它的顺序就是这样的:

容器nanobar.go => applyGo => 本体bar.go


调用了go方法后,为什么横向会有一定的动画效果呢?

观察一下nanobar的动作方法gomoveplace
其中的控制量有这么几个:

名称 作用
on 相当于布尔flag,标识了进度是否完成了
here 终点位置
dist 与终点相比的距离

实际处理流程可以这样表示:

形成动画的根本原因则是这么两个原因:

  1. 方法place(width - dist / 4)对剩余空间的细分
  2. 第58紧随其后的setTimeout(go,16),假设把x轴看成是16ms,把Y轴看成是每次细分的长度,将会得到一个图像类似于log2x(前期趋势大,后期趋势平稳,类似于动画函数中的ease-out)的表达式。

另外,引用作者原话:

Nanobar injects a style tag in your HTML head. Bar divs has class .bar, and its containers .nanobar, so you can overwrite its values.
You should know what to do with that ;)

原文地址:http://blog.51cto.com/13999332/2307577

时间: 2024-08-06 19:46:49

143行js顶部进度条最小插件-nanobar.js源码解析的相关文章

vue element-ui,上传文件加载进度条显示效果(使用定时器实现源码分享)

上传文件效果如图: 父组件相关代码 html <drag-upload ref='mychild' action="//接口相关地址" v-model="versionwareList" @submitUploadParent='formSubmit' @input='delUpload' :autoUpload="autoUpload" :visible="visible" :disabled="disabl

Html5基于SVG的扁平风格圆形进度条javascript插件教程

一.使用方法 使用该圆形进度条需要引入circleDonutChart.js文件. <script type="text/javascript" src="circleDonutChart.js"></script> 二.Html结构 你可以使用一个空的<div>元素来制作圆形进度条. <div id="example1"></div> 三.初始化插件 要制作圆形进度条,可以使用下面的方

js控制进度条到达100%跳转界面一

进度条一般在手机上用到的比较广泛,刚好最近的项目也是一直在做手机站,这个特效是手机端的一个界面,现在我把改成pc端了,进度条的快慢速度和样式可自行调节,改动也是很方便的,不多说,看代码: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>js控制进度条到达100%跳转界面</title></head>

可爱!带有数字显示的加载进度条效果插件

可爱!带有数字显示的加载进度条效果插件 有的时候,在我们的应用程序中,我们希望能够显示特定任务的百分比进度.这里分享的这款小巧的 JavaScript 插件就是实现这个功能,易于使用和定制,而且是是免费开源的. 立即下载      在线演示 有的时候,在我们的应用程序中,我们希望能够显示特定任务的百分比进度.这里分享的这款小巧的 JavaScript 插件就是实现这个功能,易于使用和定制,而且是是免费开源的. 关键字:可爱!带有数字显示的加载进度条效果插件 下载地址:https://github

Android Small插件化框架源码分析

Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github.com/wequick/Small 插件化的方案,说到底要解决的核心问题只有三个: 1.1 插件类的加载 这个问题的解决和其它插件化框架的解决方法差不多.Android的类是由DexClassLoader加载的,通过反射可以将插件包动态加载进去.Small的gradle插件生成的是.so包,在初始

Android 热修复Nuwa的原理及Gradle插件源码解析

现在,热修复的具体实现方案开源的也有很多,原理也大同小异,本篇文章以Nuwa为例,深入剖析. Nuwa的github地址 https://github.com/jasonross/Nuwa 以及用于hotpatch生成的gradle插件地址 https://github.com/jasonross/NuwaGradle 而Nuwa的具体实现是根据QQ空间的热修复方案来实现的.安卓App热补丁动态修复技术介绍.在阅读本篇文章之前,请先阅读该文章. 从QQ空间终端开发团队的文章中可以总结出要进行热更

GlusterFS源码解析—— GlusterFS 命令行常见错误

问题1 [[email protected] ~]# gluster peer status Connection failed. Please check if gluster daemon is operational. 原因:未开启glusterd服务 解决方法:开启glusterd服务 /etc/init.d/glusterd start 问题2 [[email protected] ~]# gluster peer probe server-130 peer probe: failed

android插件化-apkplugdemo源码阅读指南-10

阅读本节内容前可先了解 apkplug基础教程 本教程是基于apkplug V1.6.8 版本编写  最新开发方式以官网为准 可下载最新的apkplugdemo源码http://git.oschina.net/plug/apkplugDemos apkplugdemo演示图 一 apkplugdemo工程源码结构 src |-com.apkplugdemo.adapter             --插件列表Adapter |-com.apkplugdemo.adapter.base     

underscore.js源码解析(二)

前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这里:underscore.js源码解析(一) underscore.js源码GitHub地址: https://github.com/jashkenas/underscore/blob/master/underscore.js 本文解析的underscore.js版本是1.8.3 _.each 1