Browse Source

add Scroller

宋成林 7 years ago
parent
commit
e3b58de99a
41 changed files with 2294 additions and 269 deletions
  1. 5 1
      .gitignore
  2. 6 0
      CHANGELOG.md
  3. 4 2
      build/webpack.doc.base.conf.js
  4. 4 4
      docs/intro.md
  5. 9 6
      package.json
  6. 285 175
      scripts/mdToVue.js
  7. 1 1
      sites/demo/app.js
  8. 1 2
      sites/demo/app.vue
  9. 9 4
      sites/demo/view/index.vue
  10. 3 2
      sites/doc/app.js
  11. 1 1
      sites/doc/app.vue
  12. 29 0
      sites/doc/compents/backtop/backtop.css
  13. 1 0
      sites/doc/compents/backtop/backtop.css.map
  14. 1267 0
      sites/doc/compents/backtop/backtop.js
  15. 1 0
      sites/doc/compents/backtop/backtop.js.map
  16. 28 0
      sites/doc/compents/backtop/backtop.scss
  17. 121 0
      sites/doc/compents/backtop/backtop.vue
  18. 8 0
      sites/doc/compents/backtop/index.js
  19. 12 12
      sites/doc/info.vue
  20. 52 0
      sites/doc/root.js
  21. 33 10
      src/config.json
  22. 28 0
      src/packages/backtop/backtop.scss
  23. 121 0
      src/packages/backtop/backtop.vue
  24. 82 0
      src/packages/backtop/demo.vue
  25. 75 0
      src/packages/backtop/doc.md
  26. 8 0
      src/packages/backtop/index.js
  27. 1 1
      src/packages/buttongroup/doc.md
  28. 1 1
      src/packages/cell/cell.vue
  29. 1 1
      src/packages/cell/demo.vue
  30. 1 1
      src/packages/cell/doc.md
  31. 2 2
      src/packages/dialog/dialog.scss
  32. 2 1
      src/packages/dialog/doc.md
  33. 1 1
      src/packages/navbar/navbar.scss
  34. 20 19
      src/packages/noticebar/noticebar.scss
  35. 1 1
      src/packages/noticebar/noticebar.vue
  36. 20 4
      src/packages/rate/demo.vue
  37. 22 3
      src/packages/rate/doc.md
  38. 22 8
      src/packages/rate/rate.vue
  39. 2 2
      src/packages/shortpassword/shortpassword.scss
  40. 1 1
      src/packages/toast/demo.vue
  41. 3 3
      src/packages/toast/toast.scss

+ 5 - 1
.gitignore

@@ -9,4 +9,8 @@ coverage/
 sites/doc/view
 sites/doc/page
 package-lock.json
-yarn.lock
+yarn.lock
+docshashCache.text
+srchashCache.text
+localsrc.cache
+localdocs.cache

+ 6 - 0
CHANGELOG.md

@@ -1,6 +1,12 @@
 ## 2.0.3
 
+`2019-1-25`
+
+* :sparkles: 新增`BackTop`返回顶部组件
 * :bug: 修复`Swiper`组件 slideChangeEnd 事件的一个bug
+* :zap: `Rate`组件增加允许设置只读和间距
+* :zap: 文档MD转Vue增加文件缓存功能,提升文档预览和构建速度
+* :zap: 示例页面增加评分推荐
 
 ## 2.0.2
 

+ 4 - 2
build/webpack.doc.base.conf.js

@@ -27,14 +27,16 @@ module.exports = merge(webpackBaseConf, {
             entry:'./src',
             output:'./sites/doc/view/',
             template:'./doc-site/template.html',
-            nav:'left'
+            nav:'left',
+            needCode:true
         }),
         new mdtohtml({
             entry:'./docs',
             output:'./sites/doc/page/',
             template:'./doc-site/template.html',
             nav:'left',
-            nohead:true
+            needCode:false
+           
         }),
         new HtmlWebpackPlugin({
             template: './sites/doc/index.html',

+ 4 - 4
docs/intro.md

@@ -2,16 +2,16 @@
 
 NutUI是一套京东风格的移动端Vue组件库,开发和服务于移动Web界面的企业级前中后台产品。
 
+<div style="margin:30px 0;">
+    <img src="http://img14.360buyimg.com/uba/jfs/t1/8543/6/11560/22014/5c2c6136E8023ac0a/6abbd9de10999c48.png" width="150" alt="NutUI">
+</div>
+
 <iframe src="https://ghbtns.com/github-btn.html?user=jdf2e&repo=nutui&type=star&count=true" frameborder="0" scrolling="0" width="60px" height="20px"></iframe>
 
 <iframe src="https://ghbtns.com/github-btn.html?user=jdf2e&repo=nutui&type=watch&count=true&v=2" frameborder="0" scrolling="0" width="70px" height="20px"></iframe>
 
 <iframe src="https://ghbtns.com/github-btn.html?user=jdf2e&repo=nutui&type=fork&count=true" frameborder="0" scrolling="0" width="60px" height="20px"></iframe>
 
-<div style="margin:30px 0;">
-    <img src="http://img14.360buyimg.com/uba/jfs/t1/8543/6/11560/22014/5c2c6136E8023ac0a/6abbd9de10999c48.png" width="150" alt="NutUI">
-</div>
-
 ## 特性
 
 * 跨平台,自动转微信小程序组件(稍后上线,敬请期待)

+ 9 - 6
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@nutui/nutui",
-  "version": "2.0.2",
+  "version": "2.0.3",
   "description": "一套轻量级移动端Vue组件库",
   "typings": "dist/types/index.d.ts",
   "main": "dist/nutui.js",
@@ -59,7 +59,6 @@
     "@babel/preset-env": "7.1.0",
     "@nutui/carefree": "^0.4.0",
     "@tweenjs/tween.js": "17.2.0",
-    "istanbul-instrumenter-loader": "3.0.1",
     "@vue/test-utils": "1.0.0-beta.25",
     "autoprefixer": "9.1.3",
     "babel-eslint": "8.2.6",
@@ -73,6 +72,8 @@
     "babel-preset-env": "1.7.0",
     "babel-preset-stage-2": "6.24.1",
     "chalk": "2.4.1",
+    "chokidar": "^2.0.4",
+    "clipboard": "2.0.1",
     "copy": "0.3.2",
     "copy-webpack-plugin": "4.5.4",
     "coveralls": "^3.0.2",
@@ -83,11 +84,14 @@
     "eslint-plugin-vue": "4.7.1",
     "expect": "23.6.0",
     "file-loader": "1.1.11",
+    "folder-hash": "^2.1.2",
     "friendly-errors-webpack-plugin": "1.7.0",
     "google-code-prettify": "1.0.5",
     "has": "1.0.3",
+    "highlight.js": "^9.13.1",
     "html-webpack-plugin": "3.2.0",
     "inquirer": "6.2.0",
+    "istanbul-instrumenter-loader": "3.0.1",
     "jest": "23.5.0",
     "jest-serializer-vue": "2.0.2",
     "jsdom": "13.0.0",
@@ -103,6 +107,7 @@
     "offline-plugin": "^5.0.6",
     "optimize-css-assets-webpack-plugin": "5.0.0",
     "ora": "3.0.0",
+    "path": "^0.12.7",
     "portfinder": "1.0.17",
     "postcss-import": "12.0.0",
     "postcss-loader": "3.0.0",
@@ -123,6 +128,7 @@
     "vue-i18n": "8.1.0",
     "vue-jest": "2.6.0",
     "vue-loader": "15.4.0",
+    "vue-router": "^3.0.2",
     "vue-style-loader": "4.1.2",
     "vue-template-compiler": "2.5.17",
     "vueg": "1.3.4",
@@ -131,10 +137,7 @@
     "webpack-cli": "3.1.0",
     "webpack-dev-server": "3.1.11",
     "webpack-merge": "4.1.4",
-    "webpack-node-externals": "1.7.2",
-    "clipboard": "2.0.1",
-    "highlight.js": "^9.13.1",
-    "path": "^0.12.7"
+    "webpack-node-externals": "1.7.2"
   },
   "browserslist": [
     "> 3%",

+ 285 - 175
scripts/mdToVue.js

@@ -1,79 +1,59 @@
 const fs = require('fs');
-var path = require('path');
+const path = require('path');
+//hash获取工具
+let { hashElement } = require('folder-hash');
+//marked转换工具
 let marked = require('marked');
-let package = require("../package.json");
 if (!marked) {
     console.log('you need npm i marked -D!');
 }
-//插入 默认的 script 标签
-let jsroot = `<script>export default {
-    data(){
-        return {
-          content:'',
-          codeurl:'',
-          demourl:''
+//文件监听
+let Chokidar = require('chokidar');
+// 基本配置文件信息
+let {version} = require("../package.json");
+//vue js脚本
+//获取所有文件列表
+let fileList  = [];
+// maked文件配置
+var rendererMd = new marked.Renderer();
+//maked文件规则
+rendererMd.code = function (code, infostring, escaped) {
+    var lang = (infostring || '').match(/\S*/)[0];
+    if (this.options.highlight) {
+        var out = this.options.highlight(code, lang);
+        if (out != null && out !== code) {
+            escaped = true;
+            code = out;
         }
-      },
-      methods:{
-        closelayer(){
-          this.content = '';
-        },
-        toast(e){
-          const options = {
-            noHeader:true,
-            noFooter:true,
-            content:e.target.parentElement.outerHTML
-          }        
-          this.content = options.content;
-          let copy = this.copy;
-          new copy('.copy',{
-              target:res => {         
-                return res.previousElementSibling
-              }
-          });   
-        },  
-    dsCode(e){
-      let tag = e.target;
-      if(tag.attributes.toast){
-        this.toast(e)  
-      }      
     }
-  },
-  mounted(){   
-    //let that = this;
-    //let pre = document.querySelectorAll('pre');     
-    // for(let i=0,item;item = pre[i];i++){      
-    //   item.classList.toggle('prettyprint');   
-    //   let creatC = document.createElement('i');
-    //   creatC.setAttribute('copy','copy');    
-    //   creatC.setAttribute('data-clipboard-action','copy');
-    //   creatC.setAttribute('data-clipboard-target','code');
-    //   creatC.setAttribute('class','copy')
-    //   let creatA = document.createElement('i');
-    //   creatA.setAttribute('toast','toast');  
-    //   item.appendChild(creatC);
-    //   item.appendChild(creatA);      
-    // }
+    if (!lang) {
+        return '<pre><code>'
+            + (escaped ? code : escape(code, true))
+            + '</code></pre>';
+    }
 
-    this.$nextTick(()=>{
-        let copy = this.copy;
-        new copy('.copy',{
-            target:res => {         
-            return res.previousElementSibling
-            }
-        });    
-        let demourl = 'https://nutui.jd.com/demo.html#'+this.$route.path;
+    if (lang === 'html') {
+        code = code.replace(/@latest/g, '@' + version)
+    }
 
-        this.demourl = demourl;
-        this.qrcode.toDataURL(demourl,{width:170},(err,url)=>{
-            this.codeurl = url
-        });
-    });
-  }
-}
-</script>`;
+    return '<pre class="prettyprint"><span class="lang">' + lang + '</span><div class="code-wrapper"><code class="'
+        + this.options.langPrefix
+        + escape(lang, true)
+        + '">'
+        + (escaped ? code : escape(code, true))
+        + '</code></div><i class="copy" copy="copy" data-clipboard-action="copy" data-clipboard-target="code" title="复制代码"></i><i toast="toast" title="全屏"></i></pre>\n';
+};
+marked.setOptions({
+    renderer: rendererMd,
+    highlight: function (code) {
+        return require('highlight.js').highlightAuto(code).value;
+    },
+    tables: true
+}, res => {
+
+})
 /**
- * 
+ *  是否需要单独处理头部信息
  * @param {text} sorce 替换 头部信息 
  */
 function insert(sorce) {
@@ -88,143 +68,273 @@ function insert(sorce) {
 }
 ///创建一个空文件
 /**
- * 
+ * 修复中 
  * @param {string} output  输出路径
  * @param {string} sorce  文件源
  * @param {boole} ishasCode  是否需要二维码 
  */
 function createdFile(output, sorce, ishasCode) {
-    var pathSrc = output;
-
-    if (!ishasCode) {
+    var pathSrc = output;    
+    if (ishasCode) {
         var res = insert(sorce);
     } else {
         var res = sorce;
     }
-    fs.open(pathSrc, "w+", (err, fd) => {
-        var bufs = `<template><div  @click="dsCode">
+    var bufs = `<template><div  @click="dsCode">
         <div v-if="content" class="layer">
           <pre><span class="close-box" @click="closelayer"></span><div v-html="content"></div></pre>
-        </div>`+ res + '</div></template>' + jsroot;
-        var buf = new Buffer(bufs);
-        if (typeof fd == 'number') {
-            fs.writeSync(fd, buf, 0, buf.length, 0);
-        } else {
-            console.log(pathSrc, ' typeof fd != number 请改正文件')
-        }
-
+        </div>`+ res + `<nut-backtop :right="50" :bottom="50"></nut-backtop></div></template><script>import root from '../root.js';
+        export default {
+            mixins:[root]
+        }</script>`;
+    fs.writeFile(pathSrc,bufs,'utf8',(err)=>{
+       
     })
 }
 /**
- * 
- * @param {string} filePath  监听路径
- * @param {*} outPath 输出路径
- * @param {*} nohead 是否有头文件
+ * 目录读取,找到跟文件
+ * @fileSrc {string} 打开文件路径
+ * @callback {fn} 结束后回调函数
  */
-function fileDisplay(filePath, outPath, nohead) {
-    var rendererMd = new marked.Renderer();
-
-    rendererMd.code = function (code, infostring, escaped) {
-        var lang = (infostring || '').match(/\S*/)[0];
-        if (this.options.highlight) {
-            var out = this.options.highlight(code, lang);
-            if (out != null && out !== code) {
-                escaped = true;
-                code = out;
+function readDirRecur(fileSrc, callback) {
+    fs.readdir(fileSrc, function(err, files) {
+      var count = 0
+      var checkEnd = function() {
+        ++count == files.length && callback()
+      }  
+      files.forEach(function(file) {
+        var fullPath = fileSrc + '/' + file;  
+        fs.stat(fullPath, function(err, stats) {
+          if (stats.isDirectory()) {
+              return readDirRecur(fullPath, checkEnd);
+          } else {
+            /*not use ignore files*/
+            if(file[0] == '.') {
+  
+            } else {
+              fileList.push(fullPath)            
             }
-        }
+            checkEnd()
+          }
+        })
+      })  
+      //为空时直接回调
+      files.length === 0 && callback()
+    })
+}
+function fileReadStar(filedir,callback){
+    fs.readFile(filedir, 'utf-8', (err, data) => {
+        let html = marked(data); 
+        let mdName = "";
+        let opensName = filedir.replace(/(^.*\/|.md)/g,"");                    
+        //如果是doc文件以前缀 为
+        if (opensName === 'doc') {
+            mdName = filedir.replace(/(^.*packages\/|\/doc\.md)/g,'');
+        } else {
+            //如果不是doc命名的文件
+            mdName = opensName;
+        } 
+        callback({
+            mdName:mdName,
+            html:html
+        })   
+    });
+}
+/**
+ * 判断是否位md文件 并进行操作
+ * 判断文件是否有改动
+ * @src {string} 打开的文件目录
+ * @hasobj {obj} hash对象
+ * @callback {fn} 回调函数
+ */
+function ismd(src,hasobj,callback){
+    //判断文件类型是否是md文件    
+    let filedir = src;  
+    //return new Promise((resolve,reject)=>{
+    if (/.md$/.test(filedir)) {
+        if(hasobj.fileText){
+            let hasHObjs = hasobj;
+            hashElement(filedir).then(res=>{                
+                if(hasHObjs.fileText.indexOf(res.hash)==-1){
+                    //执行写入
+                    //同时更新缓存
+                    fs.writeFileSync(hasHObjs.cachePath,
+                        hasHObjs.fileText+'|'+res.hash
+                        ,'utf-8');
 
-        if (!lang) {
-            return '<pre><code>'
-                + (escaped ? code : escape(code, true))
-                + '</code></pre>';
+                    fileReadStar(filedir,(obj)=>{
+                        callback(obj)
+                    })
+                }
+            })
+        }else{
+            //如果没有hash 直接做下一部
+            fileReadStar(filedir,(obj)=>{
+                callback(obj)
+            })
         }
-
-        if (lang === 'html') {
-            code = code.replace(/@latest/g, '@' + package.version)
+        //对md文件存储 hash       
+        //文件读取
+        
+    }
+}
+/**
+ * 检查文件是否存折
+ * @param {*} path 
+ * @param {*} callback 
+ */
+function checkIsexists (path,callback){  
+    let pathFileName = path.replace(/[^a-zA-Z]/g,'');
+    let cacheName = './local'+pathFileName+'.cache';
+    fs.exists(cacheName, res=>{
+        if(!res){
+            fs.writeFile(cacheName,'','utf8',()=>{
+                callback(cacheName)
+            })
+        }else{
+            callback(cacheName)
         }
-
-        return '<pre class="prettyprint"><span class="lang">' + lang + '</span><code class="'
-            + this.options.langPrefix
-            + escape(lang, true)
-            + '">'
-            + (escaped ? code : escape(code, true))
-            + '</code><i class="copy" copy="copy" data-clipboard-action="copy" data-clipboard-target="code" title="复制代码"></i><i toast="toast" title="全屏"></i></pre>\n';
-    };
-
-    marked.setOptions({
-        renderer: rendererMd,
-        highlight: function (code) {
-            return require('highlight.js').highlightAuto(code).value;
-        },
-        tables: true
-    }, res => {
-
+    }) 
+}
+/**
+ * 执行文件缓存
+ */
+let outhash = [];
+function pushHash(obj){ 
+    //紧紧插入md文件hash                       
+    if(/\.md$/.test(obj.name)&&obj['hash']){
+        outhash.push(obj.hash);
+    }
+    if(obj['children']&&obj['children'].length>0){
+        obj['children'].map(res=>{
+            pushHash(res)
+        })
+    }              
+}
+//hash 对比
+/**
+ * 初始化检查是否有md文件 hash
+ * 如果没有 hash 创建一个 json文件并把 md文件 hash进去 用来做缓存
+ * 初始化获取所有md文件的 hash
+ * @param {*} path 
+ */
+function comparehash(path,callback){
+    checkIsexists(path,(cachePath)=>{       
+        //获取文件内容
+        let fileText = fs.readFileSync(cachePath,'utf-8');        
+         //获取文件 hash    
+        hashElement(path, {
+            folders: { exclude: ['.*', 'node_modules', 'test_coverage'] },
+            files: { include: ['*.md'],exclude:['*.js','*.vue','*.scss','__test__'] }
+        }).then(hash => {           
+            if(fileText){
+                //如果有内容
+                callback({
+                    fileText:fileText,
+                    cachePath:cachePath
+                })
+            }else{
+                pushHash(hash)               
+                fs.writeFileSync(cachePath,outhash.join('|'),'utf-8');
+                //如果没有内容
+                callback({
+                    fileText:fileText,
+                    cachePath:cachePath
+                })
+            }
+        })
+        .catch(error => {
+            return console.error('hashing failed:', error);
+        }); 
     })
-    fs.readdir(filePath, (res, files) => {
-        if (!res) {
-            files.forEach(filename => {
-                //获取当前文件绝对路径
-                let filedir = path.join(filePath, filename);
-                //文件写入             
-                fs.stat(filedir, (err, stats) => {
-                    if (!err) {
-                        if (stats.isDirectory()) {
-                            fileDisplay(filedir, outPath, nohead)
-                        } else {
-                            //判断文件类型是否是md文件
-                            if (/.md$/.test(filedir)) {
-                                //文件读取
-                                fs.readFile(filedir, 'utf-8', (err, data) => {
-                                    let html = marked(data);
-                                    let filedirarry = filedir.split('.');
-                                    let fdurl = filedirarry[0];
-                                    let fileNames = [];
-                                    for (let i = fdurl.length - 1; i > -1; i--) {
-                                        if (/[a-zA-Z]/.test(fdurl[i])) {
-                                            fileNames.push(fdurl[i])
-                                        } else {
-                                            fileNames.push('-')
-                                        }
-                                    }
-                                    let newName = fileNames.reverse().join('').split('-');
-                                    let resName = '';
-                                    if (newName.indexOf('doc') > -1) {
-                                        resName = newName[newName.length - 2]
-                                    } else {
-                                        resName = newName[newName.length - 1]
-                                    }
-
-                                    createdFile(outPath + '/' + resName + '.vue', html, nohead)
-                                });
-                                //文件监听
-                                let fsWatcher = fs.watchFile(filedir, {
-                                    persistent: true,
-                                    persistent: 1000
-                                }, (err, data) => {
-                                    //  console.log(err,data,filedir);
-                                    fs.readFile(filedir, 'utf-8', (err, data) => {
-                                        let html = marked(data);
-                                        let filedirarry = filedir.split('/');
-                                        let fileNames = filedirarry[filedirarry.length - 2];
-                                        createdFile(outPath + '/' + fileNames + '.vue', html, nohead)
-                                    });
-                                });
-                            }
-                        }
-                    }
+     
+}
+//文件监听
+function filelisten(param){  
+    let watcher = Chokidar.watch(param.entry,{
+        persistent: true,
+        usePolling: true,
+    })
+    let log = console.dir.bind(console);
+    let watchAction = function({event, eventPath}){      
+        // 这里进行文件更改后的操作
+        fileReadStar(eventPath,(res)=>{           
+            createdFile(param.output + res.mdName + '.vue', res.html, param.needCode)
+        })
+    }
+    watcher.on('change', path => watchAction({event: 'change', eventPath: path}))
+    .on('unlink', path => watchAction({event: 'remove', eventPath: path}));
+}
+/**
+ * 文件转md
+ * @param {obj} 
+ * @entry {string} 文件读取路径 
+ * @output {string} 文件输出路径 
+ * @needCode {boolen} 是否需要二维码 默认 true
+ */
+function fileDisplay(param) {
+    //检查文件是否第一次初始化并获取hash
+    comparehash(param.entry,(hashMsgObj)=>{
+        
+        // 获取目录下所有文件
+        readDirRecur(param.entry, function(filePath) {    
+            //文件列表        
+            fileList.map(item=>{              
+                ismd(item,hashMsgObj,res=>{
+                    //res md文件处理结果           
+                    createdFile(param.output + res.mdName + '.vue', res.html, param.needCode)
                 })
+            })    
+        });
+    });
+    
+}
+
+/**
+ * 输出的文件目录 是否存在
+ * @outPath {String} 输出的文件目录 
+ */
+function ishasOutFile(outPath,callback){
+    fs.stat(outPath,(err,res)=>{       
+        if(err){
+            fs.mkdir(outPath,err=>{
+                if(err){
+                    console.log(err)
+                }else{                  
+                    callback()
+                }               
             })
+        }else{
+            callback()
         }
     })
 }
-//md转 其他格式类型
+/**
+ * 
+ * @param {entry} 文件读取路径 
+ * @param {output} 文件输出路径 
+ * @param {needCode} 是否需要二维码 默认 true
+ */
 function MdToHtml(commomOption) {
-    // commomOption = options;
-    //获取所有的md 转html的结果
-    fileDisplay(commomOption.entry, commomOption.output, commomOption.nohead);
+    // 默认参数就这么多了,暂时没想到
+    let params = {
+        entry:'',
+        output:'',
+        needCode:true
+    }
+    params = Object.assign(params,commomOption);    
+    //检查输出路径
+    ishasOutFile(params.output,()=>{
+         //获取所有的md 转html的结果
+        fileDisplay(params);
+        //文件监听 
+        filelisten(params);
+    });
+   
 }
+//用于后期的扩展暂时没想到
 MdToHtml.prototype.apply = function (compiler) {
     //  console.log(compiler,'lls')
 };
+
 module.exports = MdToHtml;

+ 1 - 1
sites/demo/app.js

@@ -69,7 +69,7 @@ OfflinePluginRuntime.install({
     console.log('PWA缓存有更新,需要刷新页面');
 
     app.$dialog({
-      title: "您正在浏览的页面有更新,请刷新",
+      title: "当前页面有新版本,请刷新",
       noCloseBtn: true,
       noOkBtn: true,
       cancelBtnTxt: "刷新页面",

+ 1 - 2
sites/demo/app.vue

@@ -51,7 +51,6 @@ h4 {
   box-sizing: border-box;
 }
 .demo {
-  padding-left: 8px;
-  padding-right: 8px;
+  padding:0 8px 20px 8px;
 }
 </style>

+ 9 - 4
sites/demo/view/index.vue

@@ -16,6 +16,7 @@
             <a :href="'./demo.html#/'+cpt.name">
               {{cpt.name}}
               <span>{{cpt.chnName}}</span>
+              <nut-rate class="cpt-rec" v-if="cpt.star" :total="5" :value="cpt.star" :size="8" :spacing="3" :readOnly="true"></nut-rate>
             </a>
           </li>
         </template>
@@ -151,12 +152,13 @@ export default {
     border-top: 1px solid #edeef1;
     border-radius: 2px;
     background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 11 30'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M-11 0h30v30h-30z'/%3E%3Cpath d='M7.757 15C5.241 10.755 2.727 6.51.21 2.266A1.5 1.5 0 0 1 2.79.736l8 13.499c.28.472.28 1.058 0 1.53l-8 13.5a1.499 1.499 0 1 1-2.58-1.53L7.757 15z' fill='rgb(132,132,132)' /%3E%3C/g%3E%3C/svg%3E")
-      no-repeat right 15px center;
+      no-repeat right 10px center;
     background-size: 10px 10px;
     a {
-      display: block;
+      display: flex;
+      align-items:center;
       height: 100%;
-      padding: 20px;
+      padding: 20px 10px 20px 10px;
       text-decoration: none;
       color: #2e2d2d;
     }
@@ -176,7 +178,10 @@ li {
   margin: 0;
   padding: 0;
 }
-
+.cpt-rec{
+  display:inline-flex;
+  margin-left:5px;
+}
 @-webkit-keyframes swing {
   from {
     -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);

+ 3 - 2
sites/doc/app.js

@@ -4,8 +4,9 @@ import Vue from 'vue'
 import App from './App.vue'
 import router from './router';
 import copy from 'clipboard';
-
-
+import backtop from './compents/backtop/backtop.js';
+import  './compents/backtop/backtop.css';
+backtop.install(Vue);
 import 'highlight.js/styles/github.css';
 
 

+ 1 - 1
sites/doc/app.vue

@@ -9,7 +9,7 @@
           <a href="#/index" class="logo-link">
             <img src="./asset/css/i/nut.png" alt>
           </a>
-          <span class="version">{{version}}</span>
+          <span class="version">v{{version}}</span>
         </div>
         <div class="h-nav">
           <search/>

+ 29 - 0
sites/doc/compents/backtop/backtop.css

@@ -0,0 +1,29 @@
+/*! NutUI2(2.0.2) - backtop.css, 4d177b46df0af221d246, 2019-01-25T10:47:27+08:00 */
+.nut-backtop {
+  display: none;
+  line-height: 0;
+  position: fixed;
+  cursor: pointer;
+  bottom: 20px;
+  right: 10px;
+  z-index: 1111; }
+  .nut-backtop.show {
+    display: block; }
+  .nut-backtop-main {
+    -webkit-transition: all .2s ease-in-out;
+    transition: all .2s ease-in-out;
+    width: 38px;
+    height: 38px;
+    background: #FFF url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 31 39'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M1.41 0C.63 0 0 .672 0 1.5S.63 3 1.41 3h28.18C30.37 3 31 2.328 31 1.5S30.369 0 29.59 0H1.41zM17 7.5a1.5 1.5 0 0 0-3 0v30a1.5 1.5 0 1 0 3 0v-30zM8.44 12.44l-8 8a1.5 1.5 0 1 0 2.12 2.12l8-8a1.5 1.5 0 1 0-2.12-2.12z'/%3E%3Cpath d='M16.56 6.44l14 14a1.5 1.5 0 1 1-2.12 2.12l-14-14a1.5 1.5 0 1 1 2.12-2.12z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
+    background-size: 20px 20px;
+    border-radius: 50%;
+    border: 2px solid rgba(180, 180, 180, 0.5);
+    box-shadow: 0px 0px 2px 3px rgba(220, 220, 220, 0.1); }
+  .nut-backtop i {
+    color: #fff;
+    font-size: 24px;
+    padding: 8px 12px;
+    line-height: 0; }
+
+
+/*# sourceMappingURL=backtop.css.map*/

File diff suppressed because it is too large
+ 1 - 0
sites/doc/compents/backtop/backtop.css.map


File diff suppressed because it is too large
+ 1267 - 0
sites/doc/compents/backtop/backtop.js


File diff suppressed because it is too large
+ 1 - 0
sites/doc/compents/backtop/backtop.js.map


+ 28 - 0
sites/doc/compents/backtop/backtop.scss

@@ -0,0 +1,28 @@
+.nut-backtop {
+    display: none;
+    line-height: 0;
+    position: fixed;
+    cursor: pointer;
+    bottom: 20px;
+    right: 10px;
+    z-index: 1111;
+    &.show {
+        display: block;
+    }
+    &-main {
+        transition: all .2s ease-in-out;
+        width: 38px;
+        height: 38px;
+        background: #FFF url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 31 39'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M1.41 0C.63 0 0 .672 0 1.5S.63 3 1.41 3h28.18C30.37 3 31 2.328 31 1.5S30.369 0 29.59 0H1.41zM17 7.5a1.5 1.5 0 0 0-3 0v30a1.5 1.5 0 1 0 3 0v-30zM8.44 12.44l-8 8a1.5 1.5 0 1 0 2.12 2.12l8-8a1.5 1.5 0 1 0-2.12-2.12z'/%3E%3Cpath d='M16.56 6.44l14 14a1.5 1.5 0 1 1-2.12 2.12l-14-14a1.5 1.5 0 1 1 2.12-2.12z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
+        background-size: 20px 20px;
+        border-radius: 50%;
+        border: 2px solid rgba(180,180,180,.5);
+        box-shadow: 0px 0px 2px 3px rgba(220, 220, 220, .1)
+    }
+    i {
+        color: #fff;
+        font-size: 24px;
+        padding: 8px 12px;
+        line-height: 0;
+    }
+}

+ 121 - 0
sites/doc/compents/backtop/backtop.vue

@@ -0,0 +1,121 @@
+<template>
+  <div :class="['nut-backtop', {'show': backTop}]" :style="styles" @click="goto">
+    <slot>
+      <div class="nut-backtop-main"></div>
+    </slot>
+  </div>
+</template>
+<script>
+export default {
+  name: "nut-backtop",
+  props: {
+    distance: {
+      type: Number,
+      default: 200
+    },
+    bottom: {
+      type: Number,
+      default: 20
+    },
+    right: {
+      type: Number,
+      default: 10
+    },
+    duration: {
+      type: Number,
+      default: 1000
+    },
+    zIndex: {
+      type: Number,
+      default: 1111
+    }
+  },
+  data() {
+    return {
+      backTop: false
+    };
+  },
+  mounted() {
+    window.addEventListener("scroll", this.handleScroll, false);
+    window.addEventListener("resize", this.handleScroll, false);
+  },
+  beforeDestroy() {
+    window.removeEventListener("scroll", this.handleScroll, false);
+    window.removeEventListener("resize", this.handleScroll, false);
+  },
+  computed: {
+    styles() {
+      return {
+        bottom: `${this.bottom}px`,
+        right: `${this.right}px`,
+        "z-index": this.zIndex
+      };
+    }
+  },
+  methods: {
+    handleScroll() {
+      this.backTop = window.pageYOffset >= this.distance;
+    },
+    goto() {
+      const sTop =
+        document.documentElement.scrollTop || document.body.scrollTop;
+      this.scrollTop(window, sTop, 0, this.duration);
+      this.$emit("click");
+    },
+    scrollTop(el, from = 0, to, duration = 500, endCallback) {
+      this.el = el;
+      let lastTime = 0;
+      let vendors = ["webkit", "moz"];
+      for (
+        let x = 0;
+        x < vendors.length && !window.requestAnimationFrame;
+        ++x
+      ) {
+        window.requestAnimationFrame =
+          window[vendors[x] + "RequestAnimationFrame"];
+        window.cancelAnimationFrame =
+          window[vendors[x] + "CancelAnimationFrame"] ||
+          window[vendors[x] + "CancelRequestAnimationFrame"];
+      }
+
+      if (!window.requestAnimationFrame) {
+        window.requestAnimationFrame = function(callback, element) {
+          let currTime = new Date().getTime();
+          let timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
+          let id = window.setTimeout(function() {
+            callback(currTime + timeToCall);
+          }, timeToCall);
+          lastTime = currTime + timeToCall;
+          return id;
+        };
+      }
+      if (!window.cancelAnimationFrame) {
+        window.cancelAnimationFrame = function(id) {
+          clearTimeout(id);
+        };
+      }
+      const difference = Math.abs(from - to);
+      const step = Math.ceil((difference / duration) * 50);
+
+      this.scroll(from, to, step, endCallback);
+    },
+    scroll(start, end, step, endCallback) {
+      if (start === end) {
+        endCallback && endCallback();
+        return;
+      }
+
+      let d = start + step > end ? end : start + step;
+      if (start > end) {
+        d = start - step < end ? end : start - step;
+      }
+      if (this.el === window) {
+        window.scrollTo(d, d);
+      } else {
+        this.el.scrollTop = d;
+      }
+      window.requestAnimationFrame(() => this.scroll(d, end, step));
+    }
+  }
+};
+</script>

+ 8 - 0
sites/doc/compents/backtop/index.js

@@ -0,0 +1,8 @@
+import BackTop from './backtop.vue';
+import './backtop.scss';
+
+BackTop.install = function(Vue) {
+  Vue.component(BackTop.name, BackTop);
+};
+
+export default BackTop

+ 12 - 12
sites/doc/info.vue

@@ -65,22 +65,22 @@ export default {
   },
   watch: {
     packages() {
-      const compare = (obj1, obj2) => {
-        const val1 = obj1.name;
-        const val2 = obj2.name;
-        if (val1 < val2) {
-          return -1;
-        } else if (val1 > val2) {
-          return 1;
-        } else {
-          return 0;
-        }
-      };
+      // const compare = (obj1, obj2) => {
+      //   const val1 = obj1.name;
+      //   const val2 = obj2.name;
+      //   if (val1 < val2) {
+      //     return -1;
+      //   } else if (val1 > val2) {
+      //     return 1;
+      //   } else {
+      //     return 0;
+      //   }
+      // };
       let that = this;
       let tempAry = [];
       let temp = {};
       let sorts = this.sorts;
-      let sortArys = [...this.packages].sort(compare);
+      let sortArys = [...this.packages];
       sortArys.map(item => {
         let name = sorts[item.sort];
         if (!temp[name]) {

+ 52 - 0
sites/doc/root.js

@@ -0,0 +1,52 @@
+
+
+var myMixin ={
+    data(){
+        return {
+          content:'',
+          codeurl:'',
+          demourl:''
+        }
+      },
+    methods:{
+        closelayer(){
+          this.content = '';
+        },
+        toast(e){
+          const options = {
+            noHeader:true,
+            noFooter:true,
+            content:e.target.parentElement.outerHTML
+          }        
+          this.content = options.content;
+          let copy = this.copy;
+          new copy('.copy',{
+              target:res => {         
+                return res.previousElementSibling
+              }
+          });   
+        },  
+        dsCode(e){
+            let tag = e.target;
+            if(tag.attributes.toast){
+                this.toast(e)  
+            }      
+        }
+  },
+  mounted(){   
+    this.$nextTick(()=>{
+        let copy = this.copy;
+        new copy('.copy',{
+            target:res => {         
+            return res.previousElementSibling
+            }
+        });    
+        let demourl = 'https://nutui.jd.com/demo.html#'+this.$route.path;
+        this.demourl = demourl;
+        this.qrcode.toDataURL(demourl,{width:170},(err,url)=>{
+            this.codeurl = url
+        });
+    });
+  }
+}
+module.exports = myMixin;

+ 33 - 10
src/config.json

@@ -26,6 +26,7 @@
       "type": "method",
       "showDemo": true,
       "desc": "模态弹窗,支持按钮交互,支持图片弹窗。",
+      "star": 5,
       "author": "Frans"
     },
     {
@@ -46,6 +47,7 @@
       "desc": "轻提示。",
       "type": "method",
       "showDemo": true,
+      "star": 4,
       "author": "Frans"
     },
     {
@@ -56,6 +58,7 @@
       "desc": "从底部弹出的动作菜单面板。",
       "type": "component",
       "showDemo": true,
+      "star": 5,
       "author": "iris"
     },
     {
@@ -66,6 +69,7 @@
       "desc": "常用于平级区域大块内容的的收纳和展现。",
       "type": "component",
       "showDemo": true,
+      "star": 3,
       "author": "甄玉磊"
     },
     {
@@ -86,6 +90,7 @@
       "desc": "用于不同模块以之间的切换",
       "type": "component",
       "showDemo": true,
+      "star": 3,
       "author": "甄玉磊"
     },
     {
@@ -96,6 +101,7 @@
       "desc": "日历",
       "type": "component",
       "showDemo": true,
+      "star": 5,
       "author": "iris"
     },
     {
@@ -106,6 +112,7 @@
       "desc": "日期选择",
       "type": "component",
       "showDemo": true,
+      "star": 5,
       "author": "iris"
     },
     {
@@ -129,6 +136,16 @@
       "author": "wangyue"
     },
     {
+      "name": "Switch",
+      "version": "1.0.0",
+      "sort": "1",
+      "chnName": "开关",
+      "type": "component",
+      "showDemo": true,
+      "desc": "滑动开关,通过点击使按钮左右滑动,同时触发对应的开关状态",
+      "author": "Frans"
+    },
+    {
       "version": "1.0.0",
       "name": "Slider",
       "sort": "1",
@@ -136,6 +153,7 @@
       "desc": "滑动输入器,用于在数值区间/自定义区间内进行选择。",
       "type": "component",
       "showDemo": true,
+      "star": 4,
       "author": "Frans"
     },
     {
@@ -146,6 +164,7 @@
       "desc": "区间选择器组件",
       "type": "component",
       "showDemo": true,
+      "star": 4,
       "author": "famanoder"
     },
     {
@@ -156,6 +175,7 @@
       "desc": "提供多个选项集合供用户选择其中一项。",
       "type": "component",
       "showDemo": true,
+      "star": 5,
       "author": "iris"
     },
     {
@@ -246,6 +266,7 @@
       "desc": "用于快速的评级操作,或对评价进行展示。",
       "type": "component",
       "showDemo": true,
+      "star": 4,
       "author": "永无止晋"
     },
     {
@@ -256,6 +277,7 @@
       "desc": "常用于一组图片或卡片轮播,当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现。",
       "type": "component",
       "showDemo": true,
+      "star": 5,
       "author": "wangnan31"
     },
     {
@@ -276,6 +298,7 @@
       "type": "component",
       "sort": "1",
       "showDemo": true,
+      "star": 3,
       "author": "famanoder"
     },
     {
@@ -309,16 +332,6 @@
       "author": "苏子刚"
     },
     {
-      "name": "Switch",
-      "version": "1.0.0",
-      "sort": "1",
-      "chnName": "开关",
-      "type": "component",
-      "showDemo": true,
-      "desc": "滑动开关,通过点击使按钮左右滑动,同时触发对应的开关状态",
-      "author": "Frans"
-    },
-    {
       "name": "Radio",
       "version": "1.0.0",
       "sort": "1",
@@ -387,6 +400,16 @@
       "sort": "1",
       "showDemo": true,
       "author": "iris"
+    },
+    {
+      "version": "1.0.0",
+      "name": "BackTop",
+      "chnName": "回到顶部",
+      "desc": "用于页面内容高度过长,快捷回到顶部使用。",
+      "type": "component",
+      "sort": "2",
+      "showDemo": true,
+      "author": "永无止晋"
     }
   ]
 }

+ 28 - 0
src/packages/backtop/backtop.scss

@@ -0,0 +1,28 @@
+.nut-backtop {
+    display: none;
+    line-height: 0;
+    position: fixed;
+    cursor: pointer;
+    bottom: 20px;
+    right: 10px;
+    z-index: 1111;
+    &.show {
+        display: block;
+    }
+    &-main {
+        transition: all .2s ease-in-out;
+        width: 38px;
+        height: 38px;
+        background: #FFF url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 31 39'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M1.41 0C.63 0 0 .672 0 1.5S.63 3 1.41 3h28.18C30.37 3 31 2.328 31 1.5S30.369 0 29.59 0H1.41zM17 7.5a1.5 1.5 0 0 0-3 0v30a1.5 1.5 0 1 0 3 0v-30zM8.44 12.44l-8 8a1.5 1.5 0 1 0 2.12 2.12l8-8a1.5 1.5 0 1 0-2.12-2.12z'/%3E%3Cpath d='M16.56 6.44l14 14a1.5 1.5 0 1 1-2.12 2.12l-14-14a1.5 1.5 0 1 1 2.12-2.12z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
+        background-size: 20px 20px;
+        border-radius: 50%;
+        border: 2px solid rgba(180,180,180,.5);
+        box-shadow: 0px 0px 2px 3px rgba(220, 220, 220, .1)
+    }
+    i {
+        color: #fff;
+        font-size: 24px;
+        padding: 8px 12px;
+        line-height: 0;
+    }
+}

+ 121 - 0
src/packages/backtop/backtop.vue

@@ -0,0 +1,121 @@
+<template>
+  <div :class="['nut-backtop', {'show': backTop}]" :style="styles" @click="goto">
+    <slot>
+      <div class="nut-backtop-main"></div>
+    </slot>
+  </div>
+</template>
+<script>
+export default {
+  name: "nut-backtop",
+  props: {
+    distance: {
+      type: Number,
+      default: 200
+    },
+    bottom: {
+      type: Number,
+      default: 20
+    },
+    right: {
+      type: Number,
+      default: 10
+    },
+    duration: {
+      type: Number,
+      default: 1000
+    },
+    zIndex: {
+      type: Number,
+      default: 1111
+    }
+  },
+  data() {
+    return {
+      backTop: false
+    };
+  },
+  mounted() {
+    window.addEventListener("scroll", this.handleScroll, false);
+    window.addEventListener("resize", this.handleScroll, false);
+  },
+  beforeDestroy() {
+    window.removeEventListener("scroll", this.handleScroll, false);
+    window.removeEventListener("resize", this.handleScroll, false);
+  },
+  computed: {
+    styles() {
+      return {
+        bottom: `${this.bottom}px`,
+        right: `${this.right}px`,
+        "z-index": this.zIndex
+      };
+    }
+  },
+  methods: {
+    handleScroll() {
+      this.backTop = window.pageYOffset >= this.distance;
+    },
+    goto() {
+      const sTop =
+        document.documentElement.scrollTop || document.body.scrollTop;
+      this.scrollTop(window, sTop, 0, this.duration);
+      this.$emit("click");
+    },
+    scrollTop(el, from = 0, to, duration = 500, endCallback) {
+      this.el = el;
+      let lastTime = 0;
+      let vendors = ["webkit", "moz"];
+      for (
+        let x = 0;
+        x < vendors.length && !window.requestAnimationFrame;
+        ++x
+      ) {
+        window.requestAnimationFrame =
+          window[vendors[x] + "RequestAnimationFrame"];
+        window.cancelAnimationFrame =
+          window[vendors[x] + "CancelAnimationFrame"] ||
+          window[vendors[x] + "CancelRequestAnimationFrame"];
+      }
+
+      if (!window.requestAnimationFrame) {
+        window.requestAnimationFrame = function(callback, element) {
+          let currTime = new Date().getTime();
+          let timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
+          let id = window.setTimeout(function() {
+            callback(currTime + timeToCall);
+          }, timeToCall);
+          lastTime = currTime + timeToCall;
+          return id;
+        };
+      }
+      if (!window.cancelAnimationFrame) {
+        window.cancelAnimationFrame = function(id) {
+          clearTimeout(id);
+        };
+      }
+      const difference = Math.abs(from - to);
+      const step = Math.ceil((difference / duration) * 50);
+
+      this.scroll(from, to, step, endCallback);
+    },
+    scroll(start, end, step, endCallback) {
+      if (start === end) {
+        endCallback && endCallback();
+        return;
+      }
+
+      let d = start + step > end ? end : start + step;
+      if (start > end) {
+        d = start - step < end ? end : start - step;
+      }
+      if (this.el === window) {
+        window.scrollTo(d, d);
+      } else {
+        this.el.scrollTop = d;
+      }
+      window.requestAnimationFrame(() => this.scroll(d, end, step));
+    }
+  }
+};
+</script>

+ 82 - 0
src/packages/backtop/demo.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="back-top-demo">
+    <h3>《再别康桥》</h3>
+    <p>徐志摩</p>
+    <p>轻轻的我走了,正如我轻轻的来;</p>
+    <p>我轻轻的招手,作别西天的云彩。</p>
+    <p>那河畔的金柳,是夕阳中的新娘;</p>
+    <p>波光里的艳影,在我的心头荡漾。</p>
+    <p>软泥上的青荇,油油的在水底招摇;</p>
+    <p>在康桥的柔波里,</p>
+    <p>我甘心做一条水草!</p>
+    <p>那榆荫下的一潭,</p>
+    <p>不是清泉,是天上虹</p>
+    <p>揉碎在浮藻间,沉淀着彩虹似的梦。</p>
+    <p>寻梦?撑一支长蒿,</p>
+    <p>向青草更青处漫溯,</p>
+    <p>满载一船星辉,在星辉斑斓里放歌。</p>
+    <p>但我不能放歌,悄悄是别离的笙箫;</p>
+    <p>夏虫也为我沉默,沉默是今晚的康桥!</p>
+    <p>悄悄的我走了,正如我悄悄的来;</p>
+    <p>我挥一挥衣袖,不带走一片云彩。</p>
+
+    <h3>《乡愁》</h3>
+    <p>余光中</p>
+    <p>小时侯</p>
+    <p>乡愁是一枚小小的邮票</p>
+    <p>我在这头</p>
+    <p>母亲在那头</p>
+    <p>长大后</p>
+    <p>乡愁是一张窄窄的船票</p>
+    <p>我在这头</p>
+    <p>新娘在那头</p>
+    <p>之后呵</p>
+    <p>乡愁是一方矮矮的坟墓</p>
+    <p>我在外头</p>
+    <p>母亲呵在里头</p>
+    <p>而此刻</p>
+    <p>乡愁是一湾浅浅的海峡</p>
+    <p>我在这头</p>
+    <p>大陆在那头</p>
+    
+    <h3>《盼望》</h3>
+    <p>席慕容</p>
+    <p>其实我盼望的</p>
+    <p>也但是就只是那一瞬</p>
+    <p>我从没要求过你给我</p>
+    <p>你的一生</p>
+    <p>如果能在开满了栀子花的山坡上</p>
+    <p>与你相遇如果能</p>
+    <p>深深地爱过一次再别离</p>
+    <p>那麽再长久的一生</p>
+    <p>不也就只是就只是</p>
+    <p>回首时</p>
+    <p>那短短的一瞬</p>
+    <nut-backtop @click="handleClick"></nut-backtop>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  data() {
+    return {};
+  },
+  methods: {
+    handleClick() {
+      console.log("触发回到顶部");
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.back-top-demo {
+  height: 1600px;
+  line-height: 2;
+  text-align: center;
+  p {
+    font-size: 14px;
+  }
+}
+</style>

+ 75 - 0
src/packages/backtop/doc.md

@@ -0,0 +1,75 @@
+# BackTop 回到顶部
+
+用于较长的页面快捷回到顶部的组件。
+
+## 基本用法
+
+```html
+<nut-backtop>
+</nut-backtop>
+```
+
+## 设置出现位置
+
+```html
+<nut-backtop 
+  :distance="400"
+>
+</nut-backtop>
+```
+
+> “页面垂直方向滚动高度”后出现
+
+## click事件
+
+```html
+<nut-backtop 
+  @click="onClick"
+>
+</nut-backtop>
+```
+
+```javascript
+export default {
+  methods: {
+    onClick() {
+      console.log("触发回到顶部按钮")
+    }
+  }
+};
+```
+
+## 设置样式
+```html
+<nut-backtop 
+  :bottom="20"
+  :right="20"
+  :zIndex="10"
+>
+</nut-backtop>
+```
+
+
+## 设置动画持续时间
+```html
+<nut-backtop 
+  :duration="1000"  
+>
+</nut-backtop>
+```
+
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| duration | 设置动画持续时间 | Number | 1000
+| distance | “页面垂直方向滚动高度”后出现 | Number | 200
+| bottom | 设置离页面底部距离 | Number | 30
+| right | 设置离页面右边距离 | Number | 30
+| zIndex | 设置层级 | Number | 1111
+
+## Event
+| 字段 | 说明 | 回调参数 
+|----- | ----- | ----- 
+| click | 按钮点击时触发 | -

+ 8 - 0
src/packages/backtop/index.js

@@ -0,0 +1,8 @@
+import BackTop from './backtop.vue';
+import './backtop.scss';
+
+BackTop.install = function(Vue) {
+  Vue.component(BackTop.name, BackTop);
+};
+
+export default BackTop

+ 1 - 1
src/packages/buttongroup/doc.md

@@ -4,7 +4,7 @@
 
 常规按钮组
 
-```html
+```html3123123213123123123423423423431231233123123123123123123
 <nut-button-group>
   <nut-button 
     type="light"

+ 1 - 1
src/packages/cell/cell.vue

@@ -7,7 +7,7 @@
             </div>
             <div class="nut-cell-right">
                 <span class="nut-cell-desc"><slot name="desc">{{desc}}</slot></span>
-                <span class="nut-cell-icon"><slot name="icon" v-if="showIcon"><img src="data:image/svg+xml,%3Csvg viewBox='0 0 5 10' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.215 9.757l3.577-4.17a.931.931 0 0 0 0-1.173L1.215.244a.642.642 0 0 0-1.007 0 .929.929 0 0 0 0 1.172L3.283 5 .208 8.584a.93.93 0 0 0 0 1.173.643.643 0 0 0 1.007 0z' fill='%23c8c8cd'/%3E%3C/svg%3E" alt=""></slot></span>
+                <span class="nut-cell-icon"><slot name="icon" v-if="showIcon"><img src="data:image/svg+xml,%3Csvg viewBox='0 0 5 10' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.215 9.757l3.577-4.17a.931.931 0 0 0 0-1.173L1.215.244a.642.642 0 0 0-1.007 0 .929.929 0 0 0 0 1.172L3.283 5 .208 8.584a.93.93 0 0 0 0 1.173.643.643 0 0 0 1.007 0z' fill='rgb(200,200,205)'/%3E%3C/svg%3E" alt=""></slot></span>
             </div>
         </div>
     </a>

+ 1 - 1
src/packages/cell/demo.vue

@@ -18,7 +18,7 @@
             </nut-cell>
             <nut-cell :showIcon="true">
                 <span slot="title">通过Slot自定义右侧ICON</span>
-                <img slot="icon" src="data:image/svg+xml, %3Csvg version='1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M16 3.2c0-.7-.5-1.2-1.2-1.2-.3 0-.7.1-.9.4-2.4 2.5-6.2 6.8-7.7 8.5-.1.1-.2.2-.4 0L2.1 7.2c-.3-.3-.6-.4-.9-.4-.7 0-1.2.5-1.2 1.1 0 .3.1.6.3.8l.1.1 4.9 4.9c.8.8 1.6 0 2-.5 4.1-4.4 7.9-8.6 8.4-9.2.2-.3.3-.5.3-.8z' fill='%23737383'/%3E%3C/svg%3E" alt="">
+                <img slot="icon" src="data:image/svg+xml, %3Csvg version='1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M16 3.2c0-.7-.5-1.2-1.2-1.2-.3 0-.7.1-.9.4-2.4 2.5-6.2 6.8-7.7 8.5-.1.1-.2.2-.4 0L2.1 7.2c-.3-.3-.6-.4-.9-.4-.7 0-1.2.5-1.2 1.1 0 .3.1.6.3.8l.1.1 4.9 4.9c.8.8 1.6 0 2-.5 4.1-4.4 7.9-8.6 8.4-9.2.2-.3.3-.5.3-.8z' fill='rgb(115,115,131)'/%3E%3C/svg%3E" alt="">
             </nut-cell>
         </div>
     </div>

+ 1 - 1
src/packages/cell/doc.md

@@ -16,7 +16,7 @@
 ```html
 <nut-cell 
   :isLink = "true"
-  title = "左侧主标题" 
+  title = "左侧主标题" 312312312423423423423
   subTitle = "左侧副标题"
   desc="右侧描述文字">
 </nut-cell>

+ 2 - 2
src/packages/dialog/dialog.scss

@@ -63,7 +63,7 @@ body.dialog-open {
     font-size: 20px;
     text-align: center;
     text-decoration: none;
-    background: url("data:image/svg+xml, %3Csvg width='30' height='30' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23848484' fill-rule='evenodd'%3E%3Cpath d='M.44 2.56A1.5 1.5 0 1 1 2.56.44l27 27a1.5 1.5 0 1 1-2.12 2.12L15 17.123 2.56 29.56A1.5 1.5 0 1 1 .44 27.44L12.878 15 .44 2.56zM27.44.44a1.5 1.5 0 1 1 2.12 2.12l-9 9a1.5 1.5 0 1 1-2.12-2.12l9-9z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
+    background: url("data:image/svg+xml, %3Csvg width='30' height='30' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='rgb(132,132,132)' fill-rule='evenodd'%3E%3Cpath d='M.44 2.56A1.5 1.5 0 1 1 2.56.44l27 27a1.5 1.5 0 1 1-2.12 2.12L15 17.123 2.56 29.56A1.5 1.5 0 1 1 .44 27.44L12.878 15 .44 2.56zM27.44.44a1.5 1.5 0 1 1 2.12 2.12l-9 9a1.5 1.5 0 1 1-2.12-2.12l9-9z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
     background-size: 13px 13px;
     img {
         height: 13px;
@@ -91,7 +91,7 @@ body.dialog-open {
         text-decoration: none;
         border: 2px solid #FFF;
         border-radius: 50%;
-        background: url("data:image/svg+xml, %3Csvg width='30' height='30' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-rule='evenodd'%3E%3Cpath d='M.44 2.56A1.5 1.5 0 1 1 2.56.44l27 27a1.5 1.5 0 1 1-2.12 2.12L15 17.123 2.56 29.56A1.5 1.5 0 1 1 .44 27.44L12.878 15 .44 2.56zM27.44.44a1.5 1.5 0 1 1 2.12 2.12l-9 9a1.5 1.5 0 1 1-2.12-2.12l9-9z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
+        background: url("data:image/svg+xml, %3Csvg width='30' height='30' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='rgb(255,255,255)' fill-rule='evenodd'%3E%3Cpath d='M.44 2.56A1.5 1.5 0 1 1 2.56.44l27 27a1.5 1.5 0 1 1-2.12 2.12L15 17.123 2.56 29.56A1.5 1.5 0 1 1 .44 27.44L12.878 15 .44 2.56zM27.44.44a1.5 1.5 0 1 1 2.12 2.12l-9 9a1.5 1.5 0 1 1-2.12-2.12l9-9z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
         background-size: 13px 13px;
         img {
             height: 13px;

+ 2 - 1
src/packages/dialog/doc.md

@@ -88,7 +88,8 @@ this.$dialog({
 | noFooter | 是否隐藏底部按钮栏 | Boolean | false
 | noOkBtn | 是否隐藏确定按钮 | Boolean | false
 | noCancelBtn | 是否隐藏取消按钮 | Boolean | false
-| okBtnTxt | 确定按钮文案 | String | ”确定“
+| cancelBtnTxt | 取消按钮文案 | String | ”取 s消“
+| okBtnTxt | 确定按钮文案 | String | ”确 定“
 | okBtnDisabled | 禁用确定按钮 | Boolean | false
 | cancelAutoClose | 取消按钮是否默认关闭弹窗 | Boolean | true
 | textAlign | 文字对齐方向,可选值同css的text-align | String | "center"

+ 1 - 1
src/packages/navbar/navbar.scss

@@ -18,7 +18,7 @@
                 display: inline-block;
                 width: 20px;
                 height: 20px;
-                background: url("data:image/svg+xml, %3Csvg width='19' height='36' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.552 35.569a1.5 1.5 0 0 1-2.121-.017c-5.952-6.05-9.905-10.1-15.857-16.15a2 2 0 0 1 0-2.804c5.952-6.05 9.905-10.1 15.857-16.15a1.5 1.5 0 1 1 2.138 2.104C12.847 8.368 9.125 12.184 3.403 18c5.722 5.816 9.444 9.632 15.166 15.448a1.5 1.5 0 0 1-.017 2.121z' fill='%239E9E9E' fill-rule='evenodd'/%3E%3C/svg%3E") no-repeat;
+                background: url("data:image/svg+xml, %3Csvg width='19' height='36' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.552 35.569a1.5 1.5 0 0 1-2.121-.017c-5.952-6.05-9.905-10.1-15.857-16.15a2 2 0 0 1 0-2.804c5.952-6.05 9.905-10.1 15.857-16.15a1.5 1.5 0 1 1 2.138 2.104C12.847 8.368 9.125 12.184 3.403 18c5.722 5.816 9.444 9.632 15.166 15.448a1.5 1.5 0 0 1-.017 2.121z' fill='rgb(158,158,158)' fill-rule='evenodd'/%3E%3C/svg%3E") no-repeat;
                 background-size: contain;
                 vertical-align: middle;
             }

File diff suppressed because it is too large
+ 20 - 19
src/packages/noticebar/noticebar.scss


File diff suppressed because it is too large
+ 1 - 1
src/packages/noticebar/noticebar.vue


+ 20 - 4
src/packages/rate/demo.vue

@@ -10,13 +10,13 @@
             </nut-cell>
         </div>
 
-        <h4>事件</h4>
+        <h4>只读</h4>
         <div>
             <nut-cell>
-                <span slot="title"><nut-rate @click="onClick"></nut-rate></span>
+                <span slot="title"><nut-rate v-model="val2" :readOnly="true"></nut-rate></span>
             </nut-cell>
             <nut-cell>
-                <span slot="title">结果:{{result}}</span>
+                <span slot="title">结果:{{val2}}</span>
             </nut-cell>
         </div>
 
@@ -24,11 +24,21 @@
         <div>
             <nut-cell>
                 <span slot="title"><nut-rate
-                :size="35"
+                :size="30"
                 ></nut-rate></span>
             </nut-cell>
         </div>
 
+        <h4>事件</h4>
+        <div>
+            <nut-cell>
+                <span slot="title"><nut-rate @click="onClick"></nut-rate></span>
+            </nut-cell>
+            <nut-cell>
+                <span slot="title">结果:{{result}}</span>
+            </nut-cell>
+        </div>
+
         <h4>自定义ICON</h4>
         <div>
             <nut-cell>
@@ -38,6 +48,7 @@
                 ></nut-rate></span>
             </nut-cell>
         </div>
+        
     </div>
 </template>
 
@@ -46,7 +57,9 @@ export default {
     data(){
         return{
             val:4,
+            val2:2,
             result:'',
+            result2:'',
             icon1:`url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='rgb(255,0,0)' d='M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zM6.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm2.16 3H4.34a6 6 0 0 0 11.32 0z'/%3E%3C/svg%3E")`,
             icon2:`url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='rgb(255,0,0)' d='M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM6.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm7 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM7 13h6a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2z'/%3E%3C/svg%3E")`
         }
@@ -55,6 +68,9 @@ export default {
     methods:{
         onClick(idx){
             this.result = '您点击了第'+idx+'个!';
+        },
+        onClick2(idx){
+            this.result2 = '您点击了第'+idx+'个!';
         }
     }
 }

+ 22 - 3
src/packages/rate/doc.md

@@ -5,10 +5,22 @@
 ## 基础用法
 
 ```html
-<nut-rate>
+<nut-rate 
+    v-model="val"
+>
+</nut-rate>
+```
+
+只读
+```html
+<nut-rate 
+    v-model="val"
+    :readOnly="true"
+>
 </nut-rate>
 ```
 
+
 绑定事件
 
 ```html
@@ -41,7 +53,14 @@
 | 字段 | 说明 | 类型 | 默认值
 | ----- | ----- | ----- | -----
 | total | star 总数 | Number | 5
-| value | 当前 star 数,可使用 v-model 双向绑定数据 | Number | 3
+| value | 当前 star 数,可使用 v-model 双向绑定数据 | Number | 3
 | size | star 大小 | Number | 25
+| spacing | 两个star的间距 | Number | 20
+| readOnly | 是否只读 | Boolean | false
 | uncheckedIcon | 使用图标(未选中) | String | -
-| checkedIcon | 使用图标(选中) | String | -
+| checkedIcon | 使用图标(选中) | String | -
+
+## Event
+| 字段 | 说明 | 回调参数 
+|----- | ----- | ----- 
+| click | 点击star时触发 | star的index

+ 22 - 8
src/packages/rate/rate.vue

@@ -4,7 +4,12 @@
             class="nut-rate-item" 
             :class="['nut-rate-item',{'nut-rate-active':n<=current}]" 
             v-for="n in total" :key="n" @click="onClick($event,n)" 
-            :style="{'height':size+'px','width':size+'px','backgroundImage':n<=current?checkedIcon:uncheckedIcon}">
+            :style="{
+                'height':size+'px',
+                'width':size+'px',
+                'marginRight':spacing+'px',
+                'backgroundImage':n<=current?checkedIcon:uncheckedIcon
+            }">
         </span>
     </div>
 </template>
@@ -33,10 +38,14 @@ export default {
             type:String,
             default:null
         },
-        testProp:{
-            type:String,
-            default:null
-        } 
+        readOnly:{
+            type:Boolean,
+            default: false
+        },
+        spacing:{
+            type:[String,Number],
+            default: 20
+        },
     },
     data() {
         return {
@@ -48,9 +57,14 @@ export default {
     },
     methods: {
         onClick($event,idx){
-            this.current = idx;
-            this.$emit('input',idx);
-            this.$emit('click',idx);
+            if(this.readOnly){
+                this.$emit('input',this.current);
+                this.$emit('click',this.current);
+            }else{
+                this.current = idx;
+                this.$emit('input',idx);
+                this.$emit('click',idx);
+            }
         }
     }
 }

+ 2 - 2
src/packages/shortpassword/shortpassword.scss

@@ -97,7 +97,7 @@ ul {
             height: 19px;
             width: 19px;
             display: inline-block;
-            background: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d2d2d2' viewBox='0 0 30 30'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M.44 2.56A1.5 1.5 0 1 1 2.56.44l27 27a1.5 1.5 0 1 1-2.12 2.12L15 17.123 2.56 29.56A1.5 1.5 0 1 1 .44 27.44L12.878 15 .44 2.56zM27.44.44a1.5 1.5 0 1 1 2.12 2.12l-9 9a1.5 1.5 0 1 1-2.12-2.12l9-9z'/%3E%3C/g%3E%3C/svg%3E") 0 0 no-repeat;
+            background: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' fill='rgb(210,210,210)' viewBox='0 0 30 30'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M.44 2.56A1.5 1.5 0 1 1 2.56.44l27 27a1.5 1.5 0 1 1-2.12 2.12L15 17.123 2.56 29.56A1.5 1.5 0 1 1 .44 27.44L12.878 15 .44 2.56zM27.44.44a1.5 1.5 0 1 1 2.12 2.12l-9 9a1.5 1.5 0 1 1-2.12-2.12l9-9z'/%3E%3C/g%3E%3C/svg%3E") 0 0 no-repeat;
             background-size: 100% 100%;
             position: absolute;
             top: 15px;
@@ -162,7 +162,7 @@ ul {
                 display: inline-block;
                 width: 12px;
                 height: 12px;
-                background: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M.5 12c0 6.351 5.149 11.5 11.5 11.5S23.5 18.351 23.5 12 18.351.5 12 .5.5 5.649.5 12z' stroke='%230c0c0c' fill-opacity='0'/%3E%3Cpath  fill='%230c0c0c' d='M10.909 4.364h2.182v2.182h-2.182zM10.909 8.727h2.182v10.909h-2.182z'/%3E%3C/g%3E%3C/svg%3E") no-repeat;
+                background: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill-rule='evenodd'%3E%3Cpath d='M.5 12c0 6.351 5.149 11.5 11.5 11.5S23.5 18.351 23.5 12 18.351.5 12 .5.5 5.649.5 12z' stroke='rgb(12,12,12)' fill-opacity='0'/%3E%3Cpath  fill='rgb(12,12,12)' d='M10.909 4.364h2.182v2.182h-2.182zM10.909 8.727h2.182v10.909h-2.182z'/%3E%3C/g%3E%3C/svg%3E") no-repeat;
                 background-size: 100% 100%;
                 vertical-align: middle;
                 margin: -4px 5px 0 0;

+ 1 - 1
src/packages/toast/demo.vue

@@ -109,7 +109,7 @@ export default {
       this.$toast.text(msg, { duration });
     },
     sucToast(msg) {
-      this.$toast.success(msg);
+      this.$toast.success(msg, { duration:8000 });
     },
     failToast(msg) {
       this.$toast.fail(msg);

File diff suppressed because it is too large
+ 3 - 3
src/packages/toast/toast.scss