Browse Source

Merge branch 'v2-dev' of https://github.com/jdf2e/nutui into v2-dev

guoxiaoxiao8 5 years ago
parent
commit
16c1a092f5
43 changed files with 1053 additions and 205 deletions
  1. 3 1
      .postcssrc.js
  2. 2 2
      docs/international.md
  3. 1 1
      docs/start.md
  4. 1 1
      docs/theme.md
  5. 3 1
      package.json
  6. 13 0
      src/assets/svg/back.svg
  7. 15 0
      src/assets/svg/close.svg
  8. 1 0
      src/assets/svg/notice.svg
  9. 21 10
      src/config.json
  10. 26 20
      src/nutui.js
  11. 10 1
      src/packages/actionsheet/actionsheet.vue
  12. 0 1
      src/packages/actionsheet/demo.vue
  13. 23 3
      src/packages/address/address.vue
  14. 5 0
      src/packages/address/demo.vue
  15. 7 1
      src/packages/address/doc.md
  16. 2 2
      src/packages/datepicker/datepicker.vue
  17. 3 0
      src/packages/drag/demo.vue
  18. 0 2
      src/packages/drag/drag.scss
  19. 2 2
      src/packages/drag/drag.vue
  20. 90 0
      src/packages/fixednav/demo.vue
  21. 116 0
      src/packages/fixednav/doc.md
  22. 135 0
      src/packages/fixednav/fixednav.scss
  23. 79 0
      src/packages/fixednav/fixednav.vue
  24. 8 0
      src/packages/fixednav/index.js
  25. 80 0
      src/packages/gesture/demo.vue
  26. 54 0
      src/packages/gesture/doc.md
  27. 3 0
      src/packages/gesture/gesture.scss
  28. 147 0
      src/packages/gesture/index.js
  29. 6 2
      src/packages/icon/icon.vue
  30. 5 4
      src/packages/noticebar/doc.md
  31. 32 23
      src/packages/noticebar/noticebar.scss
  32. 47 33
      src/packages/noticebar/noticebar.vue
  33. 8 10
      src/packages/notify/__test__/notify.spec.js
  34. 1 3
      src/packages/notify/demo.vue
  35. 1 1
      src/packages/notify/doc.md
  36. 1 2
      src/packages/notify/index.js
  37. 0 3
      src/packages/notify/notify.vue
  38. 5 0
      src/packages/rate/rate.vue
  39. 3 3
      src/packages/tabbar/demo.vue
  40. 1 0
      src/packages/tabbar/doc.md
  41. 11 2
      src/packages/tabbar/tabbar.vue
  42. 13 3
      src/styles/variable.scss
  43. 69 68
      types/nutui.d.ts

+ 3 - 1
.postcssrc.js

@@ -2,6 +2,8 @@ module.exports = {
   plugins: {
     'postcss-import': {},
     'postcss-url': {},
-    autoprefixer: {}
+    autoprefixer: {
+      overrideBrowserslist: ['last 20 versions'] 
+    }
   }
 };

+ 2 - 2
docs/international.md

@@ -20,7 +20,7 @@ Vue.use(NutUI, {
 
 ### 按需引用组件
 
-通过 **[@nutui/babel-plugin-seperate-import](https://www.npmjs.com/package/@nutui/babel-plugin-separate-import)** 插件,我们可以根据项目需要引用 NutUI 的组件,最终只打包引用的组件,减少引入代码的体积。国际化功能同样支持按需引用的方式。
+通过 **[@nutui/babel-plugin-separate-import](https://www.npmjs.com/package/@nutui/babel-plugin-separate-import)** 插件,我们可以根据项目需要引用 NutUI 的组件,最终只打包引用的组件,减少引入代码的体积。国际化功能同样支持按需引用的方式。
 
 ```javascript
 import Vue from 'vue';
@@ -31,7 +31,7 @@ import enUS from '@nutui/nutui/dist/locales/lang/en-US';
 locale('en-US', enUS);
 ```
 
-> 请注意:通过该插件进行按需引用组件时默认引用的是构建后的文件,此时并不支持国际化的功能。如需使用组件库的国际化功能,需要在 babel 的配置文件(如.babelrc)中将 **@nutui/babel-plugin-seperate-import** 插件的 **sourceCode** 参数值设为 **true** 。这样插件将引用未经构建的源文件,同时引用的组件也不再具有 `install` 方法,请使用 `Vue.component` 对组件进行注册。
+> 请注意:通过该插件进行按需引用组件时默认引用的是构建后的文件,此时并不支持国际化的功能。如需使用组件库的国际化功能,需要在 babel 的配置文件(如.babelrc)中将 **@nutui/babel-plugin-separate-import** 插件的 **sourceCode** 参数值设为 **true** 。这样插件将引用未经构建的源文件,同时引用的组件也不再具有 `install` 方法,请使用 `Vue.component` 对组件进行注册。
 
 ```bash
 {

+ 1 - 1
docs/start.md

@@ -143,7 +143,7 @@ NutUI.install(Vue);
 
 以下两种方式都可以实现只加载用到的组件,从而减少加载的文件体积。
 
-### 1. 使用 webpack 插件 **[@nutui/babel-plugin-seperate-import](https://www.npmjs.com/package/@nutui/babel-plugin-separate-import)** (推荐)
+### 1. 使用 webpack 插件 **[@nutui/babel-plugin-separate-import](https://www.npmjs.com/package/@nutui/babel-plugin-separate-import)** (推荐)
 
 首先安装 **@nutui/babel-plugin-separate-import** 插件
 

+ 1 - 1
docs/theme.md

@@ -87,7 +87,7 @@ import Button from '@nutui/nutui/dist/packages/button/button.js';
 import '@nutui/nutui/dist/packages/button/button.scss';
 ```
 
-3.使用了插件 **[@nutui/babel-plugin-seperate-import](https://www.npmjs.com/package/@nutui/babel-plugin-separate-import)** 进行按需引用时,需修改babel的配置文件(如.babelrc),将 **style** 的设置为 **scss**。该插件将会自动引入指定组件对应的 SCSS 文件。
+3.使用了插件 **[@nutui/babel-plugin-separate-import](https://www.npmjs.com/package/@nutui/babel-plugin-separate-import)** 进行按需引用时,需修改babel的配置文件(如.babelrc),将 **style** 的设置为 **scss**。该插件将会自动引入指定组件对应的 SCSS 文件。
 
 ```bash
 {

+ 3 - 1
package.json

@@ -48,9 +48,11 @@
     "@babel/plugin-transform-runtime": "^7.9.6",
     "@commitlint/cli": "^8.0.0",
     "@commitlint/config-conventional": "^8.0.0",
-    "@nutui/cli": "^0.2.2",
+    "@nutui/cli": "^0.3.0",
+    "autoprefixer": "^9.8.4",
     "babel-plugin-istanbul": "^6.0.0",
     "gsap": "^3.2.6",
+    "hammerjs": "^2.0.8",
     "husky": "^3.0.0",
     "vue-lazyload": "^1.3.3",
     "vue-qr": "^2.2.1"

File diff suppressed because it is too large
+ 13 - 0
src/assets/svg/back.svg


File diff suppressed because it is too large
+ 15 - 0
src/assets/svg/close.svg


File diff suppressed because it is too large
+ 1 - 0
src/assets/svg/notice.svg


+ 21 - 10
src/config.json

@@ -1,13 +1,5 @@
 {
-  "sorts": [
-    "数据展示",
-    "数据录入",
-    "操作反馈",
-    "导航组件",
-    "布局组件",
-    "基础组件",
-    "业务组件"
-  ],
+  "sorts": ["数据展示", "数据录入", "操作反馈", "导航组件", "布局组件", "基础组件", "业务组件"],
   "packages": [
     {
       "name": "Cell",
@@ -651,6 +643,25 @@
       "sort": "0",
       "showDemo": true,
       "author": "yumingming"
+    },
+    {
+      "name": "FixedNav",
+      "type": "component",
+      "chnName": "悬浮导航",
+      "desc": "拖拽导航",
+      "sort": "3",
+      "showDemo": true,
+      "author": "richard1015"
+    },
+    {
+      "version": "1.0.0",
+      "name": "Gesture",
+      "type": "directive",
+      "chnName": "手势组件",
+      "desc": "基于hammer.js封装,支持移动端各种手势操作",
+      "sort": "2",
+      "showDemo": true,
+      "author": "dsj"
     }
   ]
-}
+}

+ 26 - 20
src/nutui.js

@@ -124,10 +124,14 @@ import './packages/drag/drag.scss'; // import VueQr from "./packages/qart/index.
 
 import Address from './packages/address/index.js';
 import './packages/address/address.scss';
-import Notify from "./packages/notify/index.js";
-import "./packages/notify/notify.scss";
-import CountUp from "./packages/countup/index.js";
-import "./packages/countup/countup.scss";
+import Notify from './packages/notify/index.js';
+import './packages/notify/notify.scss';
+import CountUp from './packages/countup/index.js';
+import './packages/countup/countup.scss';
+import FixedNav from './packages/fixednav/index.js';
+import './packages/fixednav/fixednav.scss';
+import Gesture from './packages/gesture/index.js';
+import './packages/gesture/gesture.scss';
 
 const packages = {
   Cell,
@@ -178,20 +182,22 @@ const packages = {
   Elevator,
   Popup,
   LeftSlip,
-  TabSelect: TabSelect,
-  LuckDraw: LuckDraw,
-  Video: Video,
-  Signature: Signature,
-  CircleProgress: CircleProgress,
-  TimeLine: TimeLine,
-  TimeLineItem: TimeLineItem,
-  SideNavBar: SideNavBar,
-  SubSideNavBar: SubSideNavBar,
-  SideNavBarItem: SideNavBarItem,
-  Drag: Drag,
-  Address: Address,
-  Notify: Notify,
-  CountUp: CountUp
+  TabSelect,
+  LuckDraw,
+  Video,
+  Signature,
+  CircleProgress,
+  TimeLine,
+  TimeLineItem,
+  SideNavBar,
+  SubSideNavBar,
+  SideNavBarItem,
+  Drag,
+  Address,
+  Notify,
+  CountUp,
+  FixedNav,
+  Gesture: Gesture
 };
 
 const components = {};
@@ -219,7 +225,7 @@ pkgList.map(item => {
   }
 });
 
-const install = function (Vue, opts = {}) {
+const install = function(Vue, opts = {}) {
   if (install.installed) return;
 
   if (opts.locale) {
@@ -275,4 +281,4 @@ export default {
   ...filters,
   ...directives,
   ...methods
-};
+};

+ 10 - 1
src/packages/actionsheet/actionsheet.vue

@@ -82,12 +82,21 @@ export default {
         if (value) {
           document.body.classList.add('nut-overflow-hidden');
         } else {
-          document.body.classList.remove('nut-overflow-hidden');
+          this.remolveLockScrool();
         }
       }
     }
   },
+  deactivated() {
+    this.remolveLockScroll();
+  },
+  destroyed(){
+    this.remolveLockScroll();
+  },
   methods: {
+    remolveLockScroll(){
+      document.body.classList.remove('nut-overflow-hidden');
+    },
     isHighlight(item) {
       return (this.chooseTagValue && this.chooseTagValue == item[this.optionTag]) || this.chooseTagValue === 0;
     },

+ 0 - 1
src/packages/actionsheet/demo.vue

@@ -77,7 +77,6 @@
     <nut-actionsheet :is-visible="isVisible5" @close="switchActionSheet('isVisible5')">
       <div slot="custom" class="custom-wrap"><span>自定义</span></div>
     </nut-actionsheet>
-    <div style="height: 400px"></div>
   </div>
 </template>
 

+ 23 - 3
src/packages/address/address.vue

@@ -11,13 +11,13 @@
     >
       <div class="title">
         <span class="arrow" @click="switchModule">
-          <nut-icon v-if="showModule == 'custom' && type == 'exist'" type="self" :url="require('../../assets/svg/arrows-back.svg')"></nut-icon>
+          <nut-icon v-if="showModule == 'custom' && type == 'exist' && backBtnIcon" type="self" :url="backBtnIcon"></nut-icon>
         </span>
 
         <span v-if="type == 'custom'">{{ customAddressTitle }}</span>
         <span v-if="type == 'exist'">{{ existAddressTitle }}</span>
 
-        <span @click="handClose('hand')"><nut-icon type="circle-cross" size="18px"></nut-icon></span>
+        <span @click="handClose('hand')"><nut-icon v-if="closeBtnIcon" size="18px" type="self" :url="closeBtnIcon"></nut-icon></span>
       </div>
 
       <!-- 请选择 -->
@@ -136,6 +136,16 @@ export default {
       // 地址选择列表前 - 选中的图标
       type: String,
       default: require('../../assets/svg/tick-red.svg')
+    },
+    closeBtnIcon:{
+      // 关闭弹框按钮 icon
+      type: String,
+      default: require('../../assets/svg/circle-cross.svg')
+    },
+    backBtnIcon:{
+      // 选择其他地址左上角返回 icon
+      type: String,
+      default: require('../../assets/svg/arrows-back.svg')
     }
   },
   data() {
@@ -305,6 +315,9 @@ export default {
     },
     // 手动关闭 点击叉号,或者蒙层
     handClose(type = 'self') {
+
+      if(!this.closeBtnIcon) return
+
       if (type == 'hand') {
         this.closeWay = 'hand';
       } else {
@@ -327,7 +340,14 @@ export default {
     },
     // 选择其他地址
     switchModule() {
-      this.showModule = this.showModule == 'exist' ? 'custom' : 'exist';
+      
+      if(this.showModule == 'exist'){
+        this.showModule = 'custom'
+      }else{
+        if(!this.backBtnIcon) return
+        this.showModule = 'exist'
+      }
+
       this.initAddress();
 
       this.$emit('switchModule', { type: this.showModule });

+ 5 - 0
src/packages/address/demo.vue

@@ -55,6 +55,7 @@
       @selected="selected3"
       :defaultIcon="defaultIcon"
       :selectedIcon="selectedIcon"
+      :closeBtnIcon="closeBtnIcon"
     ></nut-address>
 
     <nut-address
@@ -65,6 +66,7 @@
       :city="city"
       :country="country"
       :town="town"
+      :backBtnIcon="backBtnIcon"
       @onChange="onChange4"
       @close="close4"
       @selected="selected4"
@@ -104,6 +106,9 @@ export default {
       selectedIcon: require('../../assets/svg/checked.svg'),
       defaultIcon: require('../../assets/svg/unchecked.svg'),
 
+      closeBtnIcon: require('../../assets/svg/close.svg'),
+      backBtnIcon: require('../../assets/svg/back.svg'),
+
       showPopupOther: false,
       existAddress: [
         { id: 1, addressDetail: 'th ', cityName: '石景山区', countyName: '城区', provinceName: '北京', selectedAddress: true, townName: '' },

+ 7 - 1
src/packages/address/doc.md

@@ -133,7 +133,8 @@ export default {
   :isShowCustomAddress="false" 
   @selected="selected3" 
   :defaultIcon="defaultIcon" 
-  :selectedIcon='selectedIcon'>
+  :selectedIcon='selectedIcon'
+  :closeBtnIcon="closeBtnIcon">
 </nut-address>
 
 ```
@@ -146,6 +147,7 @@ export default {
         showPopupCustomImg:false,
         selectedIcon:require('../../assets/svg/checked.svg'),
         defaultIcon:require('../../assets/svg/unchecked.svg'),
+        closeBtnIcon: require('../../assets/svg/close.svg'),
         existAddress:[
           {"id":1,"addressDetail":"th ","cityName":"石景山区","countyName":"城区","provinceName":"北京","selectedAddress":true,"townName":""},
           {"id":2,"addressDetail":"12_ ","cityName":"电饭锅","countyName":"扶绥县","provinceName":"北京","selectedAddress":false,"townName":""},
@@ -200,6 +202,7 @@ export default {
     :city="city" 
     :country="country" 
     :town="town" 
+    :backBtnIcon="backBtnIcon"
     customAndExistTitle="选择其他地址"
     @onChange="onChange4" 
     @close="close4" 
@@ -225,6 +228,7 @@ export default {
       city:[{"id":7,"name":"朝阳区"},{"id":8,"name":"崇文区"},{"id":9,"name":"昌平区"},{"id":6,"name":"石景山区"}],// 市
       country:[{"id":3,"name":"八里庄街道"},{"id":9,"name":"北苑"},{"id":4,"name":"常营乡"}],// 县
       town:[], // 镇 必传值:name
+      backBtnIcon: require('../../assets/svg/back.svg'),
     };
   },
   methods: {
@@ -274,6 +278,8 @@ export default {
 | existAddress | 已存在地址列表,每个地址对象中,必传值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解释见下) | Array | []
 | defaultIcon | 已有地址列表默认图标,type=‘exist’ 时生效 | string | ''
 | selectedIcon | 已有地址列表选中图标,type=‘exist’ 时生效 | string | ''
+| closeBtnIcon | 自定义关闭弹框按钮图标 | string | -
+| backBtnIcon | 自定义地址与已有地址切换时,自定义返回的按钮图标 | string | -
 | isShowCustomAddress | 是否可以切换自定义地址选择,type=‘exist’ 时生效 | Boolean | true
 | customAddressTitle  | 自定义地址选择文案,type='custom' 时生效 | string | '请选择所在地区'
 | existAddressTitle| 已有地址文案 ,type=‘exist’ 时生效| string | '配送至'

+ 2 - 2
src/packages/datepicker/datepicker.vue

@@ -239,8 +239,8 @@ export default {
       month = this.removeChinese(month);
       let days = Array.from(Array(Utils.getMonthDays(year, month)), (v, k) => {
         if (
-          !(year == this.startDateArr[0] && month == this.startDateArr[1] && k + 1 < this.startDateArr[2]) &&
-          !(year == this.endDateArr[0] && month == this.endDateArr[1] && k + 1 > this.endDateArr[2])
+          !(year == this.startDateArr[0] && month == parseInt(this.startDateArr[1]) && (k + 1) <  parseInt(this.startDateArr[2])) &&
+          !(year == this.endDateArr[0] && month == parseInt(this.endDateArr[1]) && (k + 1) > parseInt(this.endDateArr[2]))
         ) {
           return `${k + 1}${this.chinese[2]}`;
         }

+ 3 - 0
src/packages/drag/demo.vue

@@ -9,6 +9,9 @@
     <nut-drag direction="x" :style="{ top: '200px', left: '8px' }">
       <div class="touch-dom">只能在X轴拖动</div>
     </nut-drag>
+    <nut-drag direction="y" :style="{ top: '200px', right: '100px' }">
+      <div class="touch-dom">只能在Y轴拖动</div>
+    </nut-drag>
     <h4 :style="{ top: '250px' }">自动吸边</h4>
     <nut-drag direction="x" :attract="true" :style="{ top: '300px', left: '8px' }">
       <div class="touch-dom">拖动我</div>

+ 0 - 2
src/packages/drag/drag.scss

@@ -1,8 +1,6 @@
 .nut-drag {
   position: fixed;
   display: inline-block;
-  top: 0;
-  right: 0;
   z-index: 9997 !important;
   width: fit-content;
   height: fit-content;

+ 2 - 2
src/packages/drag/drag.vue

@@ -72,12 +72,12 @@ export default {
       el.style.zIndex = this.zIndex;
       if (this.boundary.left) {
         el.style.left = this.boundary.left + 'px';
-      } else {
+      } else if (this.boundary.right) {
         el.style.right = this.boundary.right + 'px';
       }
       if (this.boundary.top) {
         el.style.top = this.boundary.top + 'px';
-      } else {
+      } else if (this.boundary.bottom) {
         el.style.bottom = this.boundary.bottom + 'px';
       }
     },

+ 90 - 0
src/packages/fixednav/demo.vue

@@ -0,0 +1,90 @@
+<template>
+  <div class="demo-list">
+    <nut-noticebar :closeMode="true" v-if="!isMobile">此 Demo 仅能在移动端浏览器体验,建议在 Android 或 iOS 设备上体验。 </nut-noticebar>
+    <!-- 基本用法 -->
+    <nut-drag direction="y" :style="{right:'0px',top:'50px'}">
+      <nut-fixednav active-text="右侧收起" un-active-text="右侧展开" :nav-list="navList" @selected="selected">
+      </nut-fixednav>
+    </nut-drag>
+    <nut-drag direction="y" :style="{left:'0px',top:'100px'}">
+      <nut-fixednav active-text="左侧收起" un-active-text="左侧展开" type="left" :nav-list="navList" @selected="selected">
+      </nut-fixednav>
+    </nut-drag>
+    <nut-drag direction="y" :style="{right:'0px',top:'150px'}">
+      <nut-fixednav :nav-list="navList" @selected="selected">
+      </nut-fixednav>
+    </nut-drag>
+    <nut-drag direction="y" :style="{left:'0px',top:'200px'}">
+      <nut-fixednav :nav-list="navList" type="left" @selected="selected">
+      </nut-fixednav>
+    </nut-drag>
+    <nut-drag direction="y" :style="{right:'0px',top:'250px'}">
+      <nut-fixednav :nav-list="navList" @selected="selected">
+      </nut-fixednav>
+    </nut-drag>
+    <nut-drag direction="y" :style="{left:'0px',top:'300px'}">
+      <nut-fixednav :nav-list="navList" type="left" @selected="selected">
+      </nut-fixednav>
+    </nut-drag>
+    <!-- 自定义用法 -->
+    <nut-drag direction="y" :style="{left:'0px',top:'300px'}">
+      <nut-fixednav :active.sync="myActive" type="left" @selected="selected">
+        <ul slot="list" class="fixed-list">
+          <li>1</li>
+          <li>2</li>
+          <li>3</li>
+          <li>4</li>
+          <li>5</li>
+        </ul>
+        <template slot="btn" @click="myActive=!myActive">
+          <img style="width:20px;height:20px"
+            src="https://img10.360buyimg.com/imagetools/jfs/t1/143466/8/1743/6993/5ef9fb50E10f30d87/993e4e681fc50cac.png" />
+          <span>{{myActive?'自定义开':'自定义关'}}</span>
+        </template>
+      </nut-fixednav>
+    </nut-drag>
+
+    <!-- 无拖拽效果 -->
+    <nut-fixednav active-text="收起" un-active-text="无法拖拽" :style="{position:'fixed',bottom:'10px',right:'0px'}"
+      :nav-list="navList" @selected="selected">
+    </nut-fixednav>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      myActive: false,
+      navList: [
+        {
+          id: 1,
+          text: '首页',
+          icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/117646/2/11112/1297/5ef83e95E81d77f05/daf8e3b1c81e3c98.png'
+        },
+        {
+          id: 2,
+          text: '分类',
+          icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/119490/8/9568/1798/5ef83e95E968c69a6/dd029326f7d5042e.png'
+        },
+        {
+          id: 3,
+          text: '购物车',
+          num: 2,
+          icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/130725/4/3157/1704/5ef83e95Eb976644f/b36c6cfc1cc1a99d.png'
+        },
+        {
+          id: 4,
+          text: '我的',
+          icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/147573/29/1603/1721/5ef83e94E1393a678/5ddf1695ec989373.png'
+        }
+      ]
+    };
+  },
+  methods: {
+    selected($event) {
+      console.log($event);
+    }
+  }
+};
+</script>

+ 116 - 0
src/packages/fixednav/doc.md

@@ -0,0 +1,116 @@
+# FixedNav 悬浮导航
+
+可拖拽的悬浮导航
+
+## 基本用法
+
+```html
+<!-- 基本用法 -->
+<nut-drag direction="y" :style="{right:'0px',top:'50px'}">
+    <nut-fixednav active-text="右侧收起" un-active-text="右侧展开" :nav-list="navList" @selected="selected">
+    </nut-fixednav>
+</nut-drag>
+<nut-drag direction="y" :style="{left:'0px',top:'100px'}">
+    <nut-fixednav active-text="左侧收起" un-active-text="左侧展开" type="left" :nav-list="navList" @selected="selected">
+    </nut-fixednav>
+</nut-drag>
+<nut-drag direction="y" :style="{right:'0px',top:'150px'}">
+    <nut-fixednav :nav-list="navList" @selected="selected">
+    </nut-fixednav>
+</nut-drag>
+<nut-drag direction="y" :style="{left:'0px',top:'200px'}">
+    <nut-fixednav :nav-list="navList" type="left" @selected="selected">
+    </nut-fixednav>
+</nut-drag>
+<nut-drag direction="y" :style="{right:'0px',top:'250px'}">
+    <nut-fixednav :nav-list="navList" @selected="selected">
+    </nut-fixednav>
+</nut-drag>
+<nut-drag direction="y" :style="{left:'0px',top:'300px'}">
+    <nut-fixednav :nav-list="navList" type="left" @selected="selected">
+    </nut-fixednav>
+</nut-drag>
+<!-- 自定义用法 -->
+<nut-drag direction="y" :style="{left:'0px',top:'300px'}">
+    <nut-fixednav :active.sync="myActive" type="left" @selected="selected">
+    <ul slot="list" class="fixed-list">
+        <li>1</li>
+        <li>2</li>
+        <li>3</li>
+        <li>4</li>
+        <li>5</li>
+    </ul>
+    <template slot="btn" @click="myActive=!myActive">
+        <img style="width:20px;height:20px"
+        src="https://img10.360buyimg.com/imagetools/jfs/t1/143466/8/1743/6993/5ef9fb50E10f30d87/993e4e681fc50cac.png" />
+        <span>{{myActive?'自定义开':'自定义关'}}</span>
+    </template>
+    </nut-fixednav>
+</nut-drag>
+
+<!-- 无拖拽效果 -->
+<nut-fixednav active-text="收起" un-active-text="无法拖拽" :style="{position:'fixed',bottom:'10px',right:'0px'}"
+    :nav-list="navList" @selected="selected">
+</nut-fixednav>
+```
+
+``` javascript
+export default {
+  data() {
+    return {
+      myActive: false,
+      navList: [
+        {
+          id: 1,
+          text: '首页',
+          icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/117646/2/11112/1297/5ef83e95E81d77f05/daf8e3b1c81e3c98.png'
+        },
+        {
+          id: 2,
+          text: '分类',
+          icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/119490/8/9568/1798/5ef83e95E968c69a6/dd029326f7d5042e.png'
+        },
+        {
+          id: 3,
+          text: '购物车',
+          num: 2,
+          icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/130725/4/3157/1704/5ef83e95Eb976644f/b36c6cfc1cc1a99d.png'
+        },
+        {
+          id: 4,
+          text: '我的',
+          icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/147573/29/1603/1721/5ef83e94E1393a678/5ddf1695ec989373.png'
+        }
+      ]
+    };
+  },
+  methods: {
+    selected($event) {
+      console.log($event);
+    }
+  }
+};
+```
+
+## Prop
+| 字段           | 说明                       | 类型    | 默认值     |
+|:---------------|:---------------------------|:--------|:-----------|
+| active         | 是否打开                   | Boolean | false      |
+| navList        | 悬浮列表内容数据           | Array   | []         |
+| active-text    | 收起列表按钮文案           | String  | '收起导航' |
+| un-active-text | 展开列表按钮文案           | String  | '快速导航' |
+| type           | 导航方向,可选值 left right | String  | 'right'     |
+
+
+## Slot
+
+| 名称 | 说明               |
+|------|--------------------|
+| btn  | 自定义按钮         |
+| list | 自定义展开列表内容 |
+
+## Event
+
+| 字段     | 说明         | 回调参数                 |
+|----------|--------------|--------------------------|
+| selected | 选择之后触发 | {item:item,$event:Event} |

+ 135 - 0
src/packages/fixednav/fixednav.scss

@@ -0,0 +1,135 @@
+.nut-fixednav {
+    height: 50px;
+    display: flex;
+    align-items: center;
+    position: relative;
+    z-index: 0;
+    width: 300px;
+
+    &.active {
+        &.left {
+            .fixed-btn img {
+                transform: rotate(180deg);
+            }
+            .fixed-list {
+                left: 0;
+            }
+        }
+        .fixed-btn {
+            img {
+                transform: rotate(0deg);
+            }
+        }
+        .fixed-list {
+            right: 0;
+        }
+    }
+
+    .fixed-btn {
+        box-sizing: border-box;
+        position: absolute;
+        right: 0;
+        z-index: 2;
+        width: 50px;
+        padding-left: 5px;
+        height: 50px;
+        background: linear-gradient(
+            135deg,
+            rgba(242, 20, 12, 1) 0%,
+            rgba(242, 39, 12, 1) 70%,
+            rgba(242, 77, 12, 1) 100%
+        );
+        border-radius: 25px 0px 0px 25px;
+        box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        > img {
+            margin-right: 5px;
+            width: 4px;
+            height: 10px;
+            flex-shrink: 0;
+            transition: all 0.3s;
+            transform: rotate(180deg);
+        }
+        > span {
+            width: 24px;
+            line-height: 13px;
+            font-size: 10px;
+            color: $fixed-bg-color;
+            flex-shrink: 0;
+        }
+    }
+    ul.fixed-list {
+        position: absolute;
+        right: -100%;
+        transition: all 0.5s;
+        z-index: 1;
+        flex-shrink: 0;
+        height: 44px;
+        background: $fixed-bg-color;
+        display: flex;
+        justify-content: space-between;
+        border-radius: 25px 0px 0px 25px;
+        box-shadow: 2px 2px 8px 0px rgba(0, 0, 0, 0.2);
+        padding: {
+            left: 20px;
+            right: 50px;
+        }
+        li {
+            position: relative;
+            flex: 1;
+            height: 100%;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            min-width: 40px;
+            flex-shrink: 0;
+            > img {
+                width: 20px;
+                height: 20px;
+                margin-bottom: 2px;
+            }
+            span {
+                font-size: 10px;
+                color: $fixed-font-color;
+            }
+            b {
+                position: absolute;
+                right: 0;
+                top: 1px;
+                height: 14px;
+                line-height: 14px;
+                font-size: 10px;
+                padding: 0 3px;
+                color: $primary-color;
+                background: $fixed-bg-color;
+                border: 1px solid $primary-color;
+                border-radius: 7px;
+                text-align: center;
+                min-width: 12px;
+            }
+        }
+    }
+    &.left {
+        .fixed-btn {
+            flex-direction: row-reverse;
+            right: auto;
+            left: 0;
+            border-radius: 0 25px 25px 0;
+            > img {
+                transform: rotate(0deg);
+            }
+        }
+        ul.fixed-list {
+            left: -100%;
+            right: auto;
+            border-radius: 0px 25px 25px 0px;
+            padding: {
+                left: 50px;
+                right: 20px;
+            }
+        }
+    }
+}

+ 79 - 0
src/packages/fixednav/fixednav.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="nut-fixednav" :class="styled">
+    <div style="position:relative;z-index:1">
+      <nut-popup v-model="defaultActive"></nut-popup>
+    </div>
+    <slot name="list">
+      <ul class="fixed-list">
+        <li v-for="(item,index) in navList" @click="selected(item,$event)" :key="item.id||index">
+          <img :src="item.icon" />
+          <span>{{item.text}}</span>
+          <b v-if="item.num">{{item.num}}</b>
+        </li>
+      </ul>
+    </slot>
+
+    <div class="fixed-btn" @click="defaultActive=!defaultActive">
+      <slot name="btn">
+        <img
+          src="https://img14.360buyimg.com/imagetools/jfs/t1/149975/30/1615/368/5ef86176Eb75bae46/5f70ae80a2d567b4.png" />
+        <span>{{defaultActive?activeText:unActiveText}}</span>
+      </slot>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  name: 'nut-fixednav',
+  props: {
+    active: {
+      type: Boolean,
+      default: false
+    },
+    navList: {
+      default: () => [],
+      type: Array
+    },
+    activeText: {
+      default: '收起导航',
+      type: String
+    },
+    unActiveText: {
+      default: '快速导航',
+      type: String
+    },
+    type: {
+      default: 'right',
+      type: String
+    }
+  },
+  computed: {
+    styled() {
+      return {
+        active: this.defaultActive,
+        [this.defaultType]: true
+      };
+    }
+  },
+  watch: {
+    defaultActive(newV, oldV) {
+      this.$emit('update:active', newV);
+    }
+  },
+  data() {
+    return {
+      defaultActive: false,
+      defaultType: ''
+    };
+  },
+  mounted() {
+    this.defaultActive = this.active;
+    this.defaultType = this.type;
+  },
+  methods: {
+    selected(item, $event) {
+      this.$emit('selected', { item, $event });
+    }
+  }
+};
+</script>

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

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

+ 80 - 0
src/packages/gesture/demo.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="container">
+    <div class="item" v-gesture:pan="test1" v-gesture:panend="test2" :style="{ left: left, top: top }">
+      <h4>基本操作</h4>
+      <p>平移</p>
+    </div>
+
+    <div class="item" v-gesture:pan.left="test3">
+      <h4>指定方向平移</h4>
+      <p>左移</p>
+    </div>
+
+    <div class="item" v-gesture:swipe.horizontal="test3">
+      <h4>指定方向滑动</h4>
+      <p>swipe</p>
+    </div>
+
+    <div class="item" v-gesture:press="test3" v-gesture:tap="test3" v-gesture:pan="test3">
+      <h4>绑定多个事件</h4>
+      <p>press、tap、pan</p>
+    </div>
+
+    <div class="show">{{ text }}</div>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      left: 0,
+      top: 70,
+      posX: 0,
+      posY: 70,
+      text: ''
+    };
+  },
+  mounted() {},
+  methods: {
+    test1(e) {
+      this.left = parseInt(this.posX) + e.deltaX + 'px';
+      this.top = parseInt(this.posY) + e.deltaY + 'px';
+    },
+    test2(e) {
+      this.posX = this.left;
+      this.posY = this.top;
+    },
+    test3(e) {
+      this.text = 'x: ' + e.deltaX + ', y: ' + e.deltaY;
+    }
+  }
+};
+</script>
+
+<style>
+.item {
+  position: absolute;
+  left: 0;
+  width: 200px;
+  height: 80px;
+  background-color: #ddd;
+}
+
+@for $i from 1 to 20 {
+  .container .item:nth-child(#{$i}) {
+    top: $i * 90 + px;
+  }
+}
+.content {
+  position: absolute;
+  left: 0;
+  top: 200px;
+  width: 100px;
+  height: 200px;
+  background-color: red;
+}
+.show {
+  position: fixed;
+  bottom: 0;
+}
+</style>

+ 54 - 0
src/packages/gesture/doc.md

@@ -0,0 +1,54 @@
+# Gesture 手势组件
+基于[hammer.js](http://hammerjs.github.io/getting-started/)封装,支持移动端各种手势操作。包括'tap', 'pan', 'pinch', 'press', 'rotate', 'swipe'
+
+## 基本用法
+```html
+<div class="item" v-gesture:pan="test1" v-gesture:panend="test2" :style="{ left: left, top: top }">
+    平移
+</div>
+```
+## 指定方向平移
+```html
+<div class="item" v-gesture:pan.left="test3">
+    左移
+</div>
+```
+## 指定方向滑动
+```html
+<div class="item" v-gesture:swipe.horizontal="test3">
+    swipe
+</div>
+```
+## 绑定多个事件
+```html
+<div class="item" v-gesture:press="test3" v-gesture:tap="test3" v-gesture:pan="test3">
+    press、tap、pan
+</div>
+<script>
+export default {
+  data() {
+    return {
+      left: 0,
+      top: 70,
+      posX: 0,
+      posY: 70
+    };
+  },
+  mounted() {},
+  methods: {
+    test1(e) {
+      this.left = parseInt(this.posX) + e.deltaX + 'px';
+      this.top = parseInt(this.posY) + e.deltaY + 'px';
+    },
+    test2(e) {
+      this.posX = this.left;
+      this.posY = this.top;
+    },
+    test3(e) {
+      console.log(e.deltaX, e.deltaY);
+    }
+  }
+};
+</script>
+
+```

+ 3 - 0
src/packages/gesture/gesture.scss

@@ -0,0 +1,3 @@
+.nut-gesture{
+
+}

+ 147 - 0
src/packages/gesture/index.js

@@ -0,0 +1,147 @@
+import Hammer from 'hammerjs';
+
+const gestures = ['tap', 'pan', 'pinch', 'press', 'rotate', 'swipe'];
+const subGestures = [
+  'panstart',
+  'panend',
+  'panmove',
+  'pancancel',
+  'pinchstart',
+  'pinchmove',
+  'pinchend',
+  'pinchcancel',
+  'pinchin',
+  'pinchout',
+  'pressup',
+  'rotatestart',
+  'rotatemove',
+  'rotateend',
+  'rotatecancel'
+];
+const directions = ['up', 'down', 'left', 'right', 'horizontal', 'vertical', 'all'];
+function verifyDirection(options) {
+  var dir = options.direction;
+  if (typeof dir === 'string') {
+    var hammerDirection = 'DIRECTION_' + dir.toUpperCase();
+    if (directions.indexOf(dir) > -1 && Hammer.hasOwnProperty(hammerDirection)) {
+      options.direction = Hammer[hammerDirection];
+    } else {
+      console.warn('[vue-hammer] invalid direction: ' + dir);
+    }
+  }
+}
+function handleDirection(event, direction) {
+  let dirArray = new Set();
+  const relations = {
+    horizontal: ['left', 'right'],
+    vertical: ['up', 'down'],
+    all: ['left', 'right', 'up', 'down']
+  };
+  direction.forEach(dir => {
+    dir = dir.toLowerCase();
+    if (relations[dir]) {
+      dirArray = new Set([...dirArray, ...relations[dir]]);
+    } else {
+      dirArray.add(dir);
+    }
+  });
+
+  if (dirArray.size === 0) {
+    return event;
+  }
+  dirArray = [...dirArray].map(dir => {
+    return event + dir;
+  });
+  return dirArray.join(' ');
+}
+
+function update(el, binding) {
+  const mc = el.hammer;
+  const event = binding.arg;
+  const dirType = subGestures.find(subGes => subGes === event) ? event : handleDirection(event, el.storage[event].direction);
+  // 删除已绑定的事件
+  if (mc.handler) {
+    mc.off(dirType, mc.handler);
+  }
+  if (typeof binding.value !== 'function') {
+    mc.handler = null;
+    console.warn(binding.arg + '请传入function类型');
+  } else {
+    mc.on(dirType, (mc.handler = binding.value));
+  }
+}
+const Gesture = {
+  name: 'gesture',
+  bind: (el, binding) => {
+    if (!el.hammer) {
+      // 是否已初始化
+      el.hammer = new Hammer.Manager(el, { inputClass: Hammer.TouchMouseInput });
+      el.hammer.domEvents = true;
+    }
+
+    const elType = binding.arg; // pan panleft ...
+    const mc = el.hammer;
+    const direction = binding.modifiers; // 方向: {right: true}
+
+    el.storage = el.storage || {}; // 记录所有事件及其方向
+    el.storage[elType] = el.storage[elType] || {};
+    el.storage[elType].direction = el.storage[elType].direction || [];
+
+    // 存储传入的方向到对应事件下
+    Object.keys(direction).forEach(keyName => {
+      if (!el.storage[elType].direction.includes(keyName)) {
+        el.storage[elType].direction.push(keyName);
+      }
+    });
+
+    let recognizerType = gestures.find(gesture => gesture === elType); // 验证传入的事件合法性
+    if (!recognizerType) {
+      return;
+    }
+    let recognizer = mc.get(recognizerType); // 获取识别器实例
+    if (!recognizer) {
+      // 创建构造器
+      recognizer = new Hammer[recognizerType.charAt(0).toUpperCase() + recognizerType.slice(1)]();
+      // 同时识别多个手势
+      recognizer.recognizeWith(mc.recognizers);
+      // 向管理器添加新的识别器实例。
+      mc.add(recognizer);
+    }
+
+    // 有方向传入时默认取第一个进行设置
+    if (el.storage[recognizerType].direction.length >= 1) {
+      let options = {
+        direction: el.storage[recognizerType].direction[0]
+      };
+      verifyDirection(options);
+      recognizer.set(options);
+    }
+  },
+  inserted: (el, binding) => {
+    update(el, binding);
+  },
+  componentUpdated: (el, binding) => {
+    update(el, binding);
+  },
+  unbind: (el, binding) => {
+    const mc = el.hammer;
+    const event = binding.arg;
+    const dirType = subGestures.find(subGes => subGes === event) ? event : handleDirection(event, el.storage[event].direction);
+    if (mc.handler) {
+      el.hammer.off(dirType, mc.handler);
+    }
+    let eventkeys = Object.keys(el.hammer.handlers);
+    let isDestroy = true;
+    eventkeys.forEach(element => {
+      if (mc.handlers[element].length > 0) {
+        isDestroy = false;
+      }
+    });
+    if (isDestroy) {
+      el.hammer.destroy();
+      el.hammer = null;
+    }
+  }
+};
+
+export default Gesture;

+ 6 - 2
src/packages/icon/icon.vue

@@ -1,8 +1,12 @@
 <template>
-  <i :class="['nut-icon', 'nut-icon-' + type]" v-html="icon" :style="{ height: size, width: size, color: color }"> </i>
+  <i
+    :class="['nut-icon', 'nut-icon-' + type]"
+    v-html="icon"
+    :style="{ height: size, width: size, color: color }"
+  ></i>
 </template>
 <script>
-const types = ['top', 'action', 'cross', 'down', 'right', 'more', 'plus', 'search', 'trolley', 'tick', 'minus', 'circle-cross'];
+const types = ['top', 'action', 'cross', 'down', 'right', 'more', 'notice', 'plus', 'search', 'trolley', 'tick', 'minus', 'circle-cross'];
 
 export default {
   name: 'nut-icon',

+ 5 - 4
src/packages/noticebar/doc.md

@@ -45,10 +45,11 @@
 | background | 导航栏的背景颜色                                           | String        | 空     |
 | delay      | 延时多少秒                                                 | String/Number | 1      |
 | scrollable | 是否可以滚动                                               | Boolean       | true   |
-| speed      | 移动375px需要用的时间                                      | Number        | 6      |
+| speed      | 滚动速率 (px/s)                                            | Number        | 50     |
 
 ## Event
 
-| 字段  | 说明             | 回调参数 |
-| ----- | ---------------- | -------- |
-| click | 外层点击事件回调 | 无       |
+| 字段  | 说明             | 回调参数     |
+| ----- | ---------------- | ------------ |
+| click | 外层点击事件回调 | event: Event |
+| close | 关闭通知栏时触发 | event: Event |

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


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


+ 8 - 10
src/packages/notify/__test__/notify.spec.js

@@ -21,14 +21,12 @@ describe('notify.vue', () => {
             expect(wrapper.find('.nut-notify').hasStyle('background', '#ffe1e1')).toBe(true);
         })
     });
-    // it('自定义时长', () => {
-    //     wrapper.setProps({
-    //         color: '#ad0000',
-    //         background: '#ffe1e1'
-    //     });
-    //     return Vue.nextTick().then(function () {
-    //         expect(wrapper.find('.nut-notify').hasStyle('color', '#ad0000')).toBe(true);
-    //         expect(wrapper.find('.nut-notify').hasStyle('background', '#ffe1e1')).toBe(true);
-    //     })
-    // });
+    it('主要通知', () => {
+        wrapper.setProps({
+            type: 'primary'
+        });
+        return Vue.nextTick().then(function () {
+            expect(wrapper.classes('nut-notify--primary')).toBe(true)
+        })
+    });
 });

+ 1 - 3
src/packages/notify/demo.vue

@@ -61,7 +61,7 @@
         </span>
       </nut-cell>
       <nut-notify :showPopup="show" type="success" msg="hello" duration="10000">
-        <!-- <span>hello</span> -->
+        <span>hello</span>
       </nut-notify>
     </div>
     <h4>修改默认配置</h4>
@@ -71,13 +71,11 @@
           <label>更改所有Notify展示时长设置为5000毫秒</label>
         </span>
       </nut-cell>
-      <nut-notify :showPopup="show" type="success"></nut-notify>
       <nut-cell :showIcon="true" :isLink="true" @click.native="resetDefaultOptions">
         <span slot="title">
           <label>恢复所有Toast提示默认配置</label>
         </span>
       </nut-cell>
-      <nut-notify :showPopup="show" type="success"></nut-notify>
     </div>
   </div>
 </template>

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

@@ -75,7 +75,7 @@ export default {
       this.show = true;
       setTimeout(() => {
         this.show = false;
-      }, 2000);
+      }, 200);
     }
 ```
 ## 修改默认配置

+ 1 - 2
src/packages/notify/index.js

@@ -3,9 +3,8 @@ import NotifyVue from './notify.vue';
 import './notify.scss';
 
 const NotifyArr = [Notify, NotifyVue];
-// console.log(NotifyArr, Notify.text('Notify'));
 NotifyArr.install = function (Vue) {
-  // Vue.prototype['$notify'] = Notify;
+  Vue.prototype['$notify'] = Notify;
   Vue.component(NotifyVue.name, NotifyVue);
 };
 

+ 0 - 3
src/packages/notify/notify.vue

@@ -20,8 +20,6 @@
 <script>
 import { overlayProps, getProps } from '../popup/index';
 import Popup from './../popup/popup.vue';
-console.log(overlayProps, 'overlayProps');
-
 export default {
   name: 'nut-notify',
   props: {
@@ -88,7 +86,6 @@ export default {
       } else {
         this.textTimer = setTimeout(() => {
           clearTimeout(this.textTimer);
-          // this.msg = '';
         }, 300);
       }
     },

+ 5 - 0
src/packages/rate/rate.vue

@@ -69,6 +69,11 @@ export default {
         this.$emit('click', idx);
       }
     }
+  },
+  watch: {
+    value(newVal, oldVal) {
+       this.current = newVal;
+    }
   }
 };
 </script>

+ 3 - 3
src/packages/tabbar/demo.vue

@@ -57,7 +57,7 @@ export default {
           curr: true,
           icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/115926/10/6303/6603/5eb93bdeE8951c288/d277b2a668645e73.png',
           activeIcon: 'https://img12.360buyimg.com/imagetools/jfs/t1/126024/30/1055/6952/5eb93be3E45d921c4/3060f25d49fc4ae7.png',
-          href: '###'
+          href: 'https://m.jd.com'
         },
         {
           tabTitle: '分类',
@@ -79,14 +79,14 @@ export default {
           num: 2,
           icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/126465/3/1055/5848/5eb93f31E0ce4f65b/087c08eaeef97b64.png',
           activeIcon: 'https://img10.360buyimg.com/imagetools/jfs/t1/111251/23/6376/6446/5eb93f2dE659da502/41fea546d36b8aaa.png',
-          href: '###'
+          href: 'https://m.jd.com'
         },
         {
           tabTitle: '我的',
           curr: false,
           icon: 'http://img20.360buyimg.com/uba/jfs/t1/20004/20/1045/3620/5c0f3d61Eaaec1670/9e59db63983b7b9f.jpg',
           activeIcon: 'http://img14.360buyimg.com/uba/jfs/t1/23967/14/1072/6714/5c0f3d61E0ad8991e/8f741953f6e38f15.jpg',
-          href: '###'
+          href: 'https://m.jd.com'
         }
       ]
     };

+ 1 - 0
src/packages/tabbar/doc.md

@@ -160,6 +160,7 @@ export default {
 | type | 页签栏的样式 based/card:based是默认样式如吸底样式,card类型每个卡片间有边界线 | String | based
 | tabbar-list | 渲染数据 ,兼容 tabbar-list 和 tabbarList| Array | []
 | bottom | 是否固定在页面底部 |Booble|false|
+| replace | replace为true的时候,跳转url以替换的形式进行 |Boolean|false|
 
 ### tabbar-list
 

+ 11 - 2
src/packages/tabbar/tabbar.vue

@@ -6,7 +6,6 @@
       :class="[{ 'curr': index == currIndex }, type]"
       :key="value.tabTitle"
       v-on:click="switchTabs(value, index)"
-      :href="value.href"
     >
       <span class="icon-box">
         <b class="tips num" v-if="value.num && value.num <= 99">{{ value.num }}</b>
@@ -36,6 +35,10 @@ export default {
     type: {
       type: String,
       default: 'based'
+    },
+    replace:{
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -66,8 +69,14 @@ export default {
     },
     switchTabs: function(value, index) {
       this.currIndex = index;
+      if(this.replace){ //替换url
+        window.location.replace(value.href);
+      }else{
+        if(value.href){
+          window.location.href = value.href;
+        }
+      }
       this.$emit('tab-switch', value, index);
-      this.$emit('tabSwitch', value, index); //兼容以前驼峰法
     }
   }
 };

+ 13 - 3
src/styles/variable.scss

@@ -10,7 +10,8 @@ $dark-color: #dadada !default;
 // ---- base ----
 $body-background: #f6f6f6 !default;
 $mask-bg: rgba(0, 0, 0, 0.5) !default;
-$font-family: PingHei, 'Lucida Grande', 'Lucida Sans Unicode', STHeiti, Helvetica, Arial, Verdana, 'sans-serif', 'PingHei-light', SimHei, 'Droid Sans' !default;
+$font-family: PingHei, "Lucida Grande", "Lucida Sans Unicode", STHeiti, Helvetica, Arial, Verdana, "sans-serif",
+    "PingHei-light", SimHei, "Droid Sans" !default;
 $font-size-base: 14px !default;
 $font-size-small: 12px !default;
 $font-size-large: 16px !default;
@@ -60,7 +61,11 @@ $btn-gradient-color: #fff !default;
 $btn-gradient-start-color: #ff4f18;
 $btn-gradient-end-color: #f20000;
 $btn-gradient-bg: linear-gradient(315deg, $btn-gradient-start-color 0%, $btn-gradient-end-color 100%) !default;
-$btn-gradient-active-bg: linear-gradient(315deg, darken($btn-gradient-start-color, 10%) 0%, darken($btn-gradient-end-color, 10%) 100%) !default;
+$btn-gradient-active-bg: linear-gradient(
+    315deg,
+    darken($btn-gradient-start-color, 10%) 0%,
+    darken($btn-gradient-end-color, 10%) 100%
+) !default;
 $btn-default-color: $normal-color !default;
 $btn-default-bg: #fff !default;
 $btn-default-border: $border-color-dark !default;
@@ -78,7 +83,7 @@ $zindex-actionsheet: 10001 !default;
 $zindex-dialog: 10000 !default;
 $zindex-picker: 10050 !default;
 // ---- Assets path ----
-$assetsPath: '../../assets' !default;
+$assetsPath: "../../assets" !default;
 // ---- Stepper ----
 $stepper-color: #333 !default;
 $stepperbar-width: 11px !default;
@@ -93,3 +98,8 @@ $notify-primary-background-color: #1989fa;
 $notify-success-background-color: #07c160;
 $notify-danger-background-color: #ee0a24;
 $notify-warning-background-color: #ff976a;
+
+// Fixed
+
+$fixed-bg-color: #fff;
+$fixed-font-color: #333;

+ 69 - 68
types/nutui.d.ts

@@ -15,71 +15,72 @@ export const locale: (l: any) => void;
 
 export function install(vue: typeof Vue, options: InstallationOptions): void;
 
-export declare class ActionSheet extends UIComponent { }
-export declare class Badge extends UIComponent { }
-export declare class Button extends UIComponent { }
-export declare class ButtonGroup extends UIComponent { }
-export declare class Calendar extends UIComponent { }
-export declare class Cell extends UIComponent { }
-export declare class CheckBox extends UIComponent { }
-export declare class CheckBoxGroup extends UIComponent { }
-export declare class Col extends UIComponent { }
-export declare class DatePicker extends UIComponent { }
-export declare class Dialog extends UIComponent { }
-export declare class Flex extends UIComponent { }
-export declare class Grid extends UIComponent { }
-export declare class GridCol extends UIComponent { }
-export declare class GridRow extends UIComponent { }
-export declare class Icon extends UIComponent { }
-export declare class ImagePicker extends UIComponent { }
-export declare class Menu extends UIComponent { }
-export declare class NavBar extends UIComponent { }
-export declare class NoticeBar extends UIComponent { }
-export declare class Picker extends UIComponent { }
-export declare class Price extends UIComponent { }
-export declare class Progress extends UIComponent { }
-export declare class Radio extends UIComponent { }
-export declare class RadioGroup extends UIComponent { }
-export declare class Range extends UIComponent { }
-export declare class Rate extends UIComponent { }
-export declare class Row extends UIComponent { }
-export declare class SearchBar extends UIComponent { }
-export declare class ShortPassword extends UIComponent { }
-export declare class Skeleton extends UIComponent { }
-export declare class Slider extends UIComponent { }
-export declare class Stepper extends UIComponent { }
-export declare class Steps extends UIComponent { }
-export declare class Swiper extends UIComponent { }
-export declare class Switch extends UIComponent { }
-export declare class Tab extends UIComponent { }
-export declare class Tabbar extends UIComponent { }
-export declare class TabPanel extends UIComponent { }
-export declare class Toast extends UIComponent { }
-export declare class BackTop extends UIComponent { }
-export declare class Scroller extends UIComponent { }
-export declare class CountDown extends UIComponent { }
-export declare class Uploader extends UIComponent { }
-export declare class TextInput extends UIComponent { }
-export declare class TextBox extends UIComponent { }
-export declare class Avatar extends UIComponent { }
-export declare class Infiniteloading extends UIComponent { }
-export declare class Lazyload extends UIComponent { }
-export declare class Elevator extends UIComponent { }
-export declare class LeftSlip extends UIComponent { }
-export declare class TabSelect extends UIComponent { }
-export declare class Popup extends UIComponent { }
-
-export declare class LuckDraw extends UIComponent { }
-export declare class Video extends UIComponent { }
-export declare class Signature extends UIComponent { }
-export declare class CircleProgress extends UIComponent { }
-export declare class TimeLine extends UIComponent { }
-export declare class TimeLineItem extends UIComponent { }
-export declare class SideNavBar extends UIComponent { }
-export declare class SubSideNavBar extends UIComponent { }
-export declare class SideNavBarItem extends UIComponent { }
-export declare class Qart extends UIComponent { }
-export declare class Drag extends UIComponent { }
-export declare class Address extends UIComponent { }
-export declare class Notify extends UIComponent { }
-export declare class CountUp extends UIComponent { }
+export declare class ActionSheet extends UIComponent {}
+export declare class Badge extends UIComponent {}
+export declare class Button extends UIComponent {}
+export declare class ButtonGroup extends UIComponent {}
+export declare class Calendar extends UIComponent {}
+export declare class Cell extends UIComponent {}
+export declare class CheckBox extends UIComponent {}
+export declare class CheckBoxGroup extends UIComponent {}
+export declare class Col extends UIComponent {}
+export declare class DatePicker extends UIComponent {}
+export declare class Dialog extends UIComponent {}
+export declare class Flex extends UIComponent {}
+export declare class Grid extends UIComponent {}
+export declare class GridCol extends UIComponent {}
+export declare class GridRow extends UIComponent {}
+export declare class Icon extends UIComponent {}
+export declare class ImagePicker extends UIComponent {}
+export declare class Menu extends UIComponent {}
+export declare class NavBar extends UIComponent {}
+export declare class NoticeBar extends UIComponent {}
+export declare class Picker extends UIComponent {}
+export declare class Price extends UIComponent {}
+export declare class Progress extends UIComponent {}
+export declare class Radio extends UIComponent {}
+export declare class RadioGroup extends UIComponent {}
+export declare class Range extends UIComponent {}
+export declare class Rate extends UIComponent {}
+export declare class Row extends UIComponent {}
+export declare class SearchBar extends UIComponent {}
+export declare class ShortPassword extends UIComponent {}
+export declare class Skeleton extends UIComponent {}
+export declare class Slider extends UIComponent {}
+export declare class Stepper extends UIComponent {}
+export declare class Steps extends UIComponent {}
+export declare class Swiper extends UIComponent {}
+export declare class Switch extends UIComponent {}
+export declare class Tab extends UIComponent {}
+export declare class Tabbar extends UIComponent {}
+export declare class TabPanel extends UIComponent {}
+export declare class Toast extends UIComponent {}
+export declare class BackTop extends UIComponent {}
+export declare class Scroller extends UIComponent {}
+export declare class CountDown extends UIComponent {}
+export declare class Uploader extends UIComponent {}
+export declare class TextInput extends UIComponent {}
+export declare class TextBox extends UIComponent {}
+export declare class Avatar extends UIComponent {}
+export declare class Infiniteloading extends UIComponent {}
+export declare class Lazyload extends UIComponent {}
+export declare class Elevator extends UIComponent {}
+export declare class LeftSlip extends UIComponent {}
+export declare class TabSelect extends UIComponent {}
+export declare class Popup extends UIComponent {}
+export declare class LuckDraw extends UIComponent {}
+export declare class Video extends UIComponent {}
+export declare class Signature extends UIComponent {}
+export declare class CircleProgress extends UIComponent {}
+export declare class TimeLine extends UIComponent {}
+export declare class TimeLineItem extends UIComponent {}
+export declare class SideNavBar extends UIComponent {}
+export declare class SubSideNavBar extends UIComponent {}
+export declare class SideNavBarItem extends UIComponent {}
+export declare class Qart extends UIComponent {}
+export declare class Drag extends UIComponent {}
+export declare class Address extends UIComponent {}
+export declare class Notify extends UIComponent {}
+export declare class CountUp extends UIComponent {}
+export declare class FixedNav extends UIComponent {}
+export declare class Gesture extends UIComponent {}