ソースを参照

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

yewenwen 5 年 前
コミット
8b069e6535

+ 1 - 0
.gitignore

@@ -21,3 +21,4 @@ lib/plugin/cli/dist_cli/
 lib/plugin/cli/site/doc/view/
 lib/plugin/cli/site/doc/page/
 yarn.lock
+/test_script

+ 0 - 5
.huskyrc

@@ -1,5 +0,0 @@
-{
-  "hooks": {
-    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
-  }
-}

+ 6 - 14
package.json

@@ -17,28 +17,20 @@
     "build:site": "nutui-cli build-site",
     "clean": "nutui-cli clean",
     "add": "nutui-cli add",
-    "lint": "nutui-cli lint",
     "test": "cross-env NODE_ENV=test nyc mocha-webpack --webpack-config node_modules/@nutui/cli/dist_cli/webpack/test.config.js  --require node_modules/@nutui/cli/dist_cli/test/setup.js src/packages/*/__test__/**.spec.js",
     "coveralls": "cat ./coverage/lcov.info | coveralls",
     "test:watch": "npm run test --watch",
-    "prettier:check": "prettier -l src/**/*.{ts,js,vue,scss}",
     "prettier:fix": "prettier --write src/**/*.{ts,js,vue,scss}"
   },
+  "husky": {
+    "hooks": {
+      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
+    }
+  },
   "repository": {
     "type": "git",
     "url": "https://github.com/jdf2e/nutui.git"
   },
-  "eslintConfig": {
-    "root": true,
-    "extends": [
-      "./eslint-config.js"
-    ]
-  },
-  "stylelint": {
-    "extends": [
-      "./stylelint-config.js"
-    ]
-  },
   "keywords": [
     "nutui",
     "nutui2",
@@ -56,7 +48,7 @@
     "@babel/plugin-transform-runtime": "^7.9.6",
     "@commitlint/cli": "^8.0.0",
     "@commitlint/config-conventional": "^8.0.0",
-    "@nutui/cli": "^0.1.9",
+    "@nutui/cli": "^0.2.0",
     "@vue/composition-api": "^0.5.0",
     "babel-plugin-istanbul": "^6.0.0",
     "gsap": "^3.2.6",

+ 2 - 2
src/packages/imagepicker/demo.vue

@@ -39,8 +39,8 @@ export default {
       if (data.code == 1) {
         alert('upload');
       }
-      console.log(this.imgList2);
-      console.log(data); //code 1 自动上传  2 不上传只展示图片  3 删除图片  4 预览图片
+      //console.log(this.imgList2);
+      //console.log(data); //code 1 自动上传  2 不上传只展示图片  3 删除图片  4 预览图片
     }
   }
 };

+ 4 - 4
src/packages/imagepicker/imagepicker.vue

@@ -119,13 +119,13 @@ export default {
               src: evt.target.result
             });
             event.target.value = '';
-            self.$emit('imgMsg', {
-              code: 2,
-              msg: fileArr
-            });
           };
           reader.readAsDataURL(item);
         });
+        self.$emit('imgMsg', {
+            code: 2,
+            msg: fileArr
+        });
       }
     },
     preview(id) {

+ 104 - 47
src/packages/popup/__test__/popup.spec.js

@@ -1,52 +1,109 @@
-import { mount } from '@vue/test-utils'
-import popup from '../popup.vue'
+import { mount } from '@vue/test-utils';
+import Popup ,{popupProps} from '../popup.vue';
+import { overlayProps } from '../overlay/overlay.vue';
 import Vue from 'vue';
-// import overlay from "../overlay.vue";
-import Icon from '../../icon/icon.vue';
-describe('Menu.vue',() => {
-    const wrapper = mount(popup, {
-        
-    });
+let wrapper,allProps = {}; 
+Object.assign(allProps,overlayProps,popupProps)
+function getProps() {
+  let obj = {};
+
+  Object.keys(allProps).forEach(res => {
+    if (res !== 'value') {
+      obj[res] = this[res];
+    }
+  });
+  return obj;
+}
+describe('popup.vue', () => {
+  afterEach(function() {
+    wrapper.destroy();
+  });
+  const component = {
+    template: `<div>
+                <popup v-model='popupVal' v-bind="maskProps" ></popup>
+            </div>`,
+    components: {
+      Popup
+    },
+    data() {
+      return {
+        maskProps: getProps.apply(this),
+        popupVal: this.value
+      };
+    },
+    watch: {
+      value(v) {
+        this.popupVal = v;
+      }
+    },
+    props: { ...allProps, closeable: Boolean }
+  };
+
+    it('1.render popup && overlay', async function() {
+      wrapper = mount(component, { propsData: { value: true } });
+      wrapper.setProps({ value: true });
+      await Vue.nextTick();
+      expect(wrapper.find('.popup-box').isVisible()).toBe(true);
+      expect(wrapper.find('.nut-mask').isVisible()).toBe(true);
 
-    it('1.判断是否显示内容',() => {
-        wrapper.setData({
-            value:true
-        }); 
-        return Vue.nextTick().then(function() {
-            expect(wrapper.classes()).toContain('popup-box')
-        }) 
     });
-    it('2.判断弹出位置',() => {
-        wrapper.setData({ 
-            position:"top"
-        }); 
-        return Vue.nextTick().then(function() {
-            expect(wrapper.classes()).toContain('popup-top')
-        }) 
+
+    it('2.test props overlay', async function() {
+      wrapper = mount(component, { propsData: { value: true, overlay: false } });
+      await Vue.nextTick();
+      expect(wrapper.contains('.nut-mask')).toBe(false);
+
     });
-    it('3.判断是否有关闭图标',() => {
-        wrapper.setData({ 
-            closeable:true
-        });  Icon
-        let i = wrapper.find('.nutui-popup__close-icon')
-        return Vue.nextTick().then(function() {
-            expect(i.is(Icon)).toBe(true)
-        }) 
+
+    it('3.test props lockScroll', async function() {
+      const wrapper1 = mount(component, { propsData: { value: true } });
+      const wrapper2 = mount(component, { propsData: { value: true } });
+      expect(document.body.classList.contains('nut-overflow-hidden')).toBe(true);
+
+      wrapper1.destroy();
+      await Vue.nextTick();
+      expect(document.body.classList.contains('nut-overflow-hidden')).toBe(true);
+      wrapper2.destroy();
+      await Vue.nextTick();
+      expect(document.body.classList.contains('nut-overflow-hidden')).toBe(false);
+
     });
-    // it('4.判断点击关闭按钮',() => {
-    //     wrapper.setData({ 
-    //         closeable:true
-    //     }); 
-    //     let i = wrapper.find('.nutui-popup__close-icon');
-    //     i.trigger('click')
-    //     console.log()
-    //     return Vue.nextTick().then(function() {
-    //         setTimeout(()=>{
-    //             expect(wrapper.contains(popup)).toBe(false)
-    //         },wrapper.duration*1000)           
-    //     }) 
-    // });
-
- 
- 
-});
+
+  it('4.test closeOnClickOverlay', async function() {
+    wrapper = mount(component, { propsData: { value: true, closeOnClickOverlay: true } });
+    await Vue.nextTick();
+    wrapper.find('.nut-mask').trigger('click');
+    await Vue.nextTick();
+    const duration = wrapper.vm.duration * 1500; 
+    await new Promise(resolve => {
+      setTimeout(() => resolve(), duration);
+    }); 
+    
+    expect(wrapper.find('.nut-mask').isVisible() || wrapper.find('.popup-box').isVisible()).toBe(false); 
+  });
+  it('5.test closeOnClickOverlay', async function() {
+    wrapper = mount(component, { propsData: { value: true, closeable: true } });
+    await Vue.nextTick();
+    let i = wrapper.find('.nutui-popup__close-icon');
+    i.trigger('click');
+    await Vue.nextTick();
+    await new Promise(resolve => {
+      setTimeout(() => resolve(), wrapper.duration * 1000);
+    });  
+     
+    expect(wrapper.find('.popup-box').isVisible()).toBe(false);
+  });
+
+   
+  it('6.test top ', async function()  {
+      wrapper = mount(component, { propsData: { value: true, position:"top"}});
+      await Vue.nextTick();  
+      expect(wrapper.find('.popup-box').classes()).toContain('popup-top')
+  });
+  it('7. zindex ',async function()  {
+    wrapper = mount(component, { propsData: { value: true,zIndex:999}});
+      const  wrapper2 = mount(component, { propsData: { value: true}});
+      await Vue.nextTick();  
+      expect(wrapper.find('.popup-box').vm.zIndex).toBe(999) 
+  });
+});

+ 16 - 20
src/packages/popup/overlay/overlay-manager.js

@@ -3,9 +3,8 @@ import overlayComponent from "./overlay.vue";
 
 let modalStack = [];
 let _zIndex = 2000;
-
-const overlayManager = {
-  overlay: null,
+let overlay;
+const overlayManager = { 
 
   lockCount: 0,
 
@@ -17,27 +16,27 @@ const overlayManager = {
   },
 
   updateOverlay() {
-    const { overlay, clickHandle, topStack } = overlayManager;
+    const {  clickHandle, topStack } = overlayManager;
     if (!overlay) {
-      overlayManager.overlay = mount(overlayComponent, {
+      overlay = mount(overlayComponent, {
         nativeOn: {
           click: clickHandle,
         },
       });
-    }
-
+    } 
+ 
     if (topStack) {
       const { vm, config } = topStack;
       const el = vm.$el;
       el && el.parentNode && el.parentNode.nodeType !== 11
         ? el.parentNode.appendChild(overlay.$el)
         : document.body.appendChild(overlay.$el);
-
-      Object.assign(overlayManager.overlay, config, {
+      
+      Object.assign(overlay, config, {
         value: true,
-      });
-    } else {
-      overlayManager.overlay.value = false;
+      }); 
+    } else { 
+      overlay.value = false;
     }
   },
 
@@ -45,8 +44,6 @@ const overlayManager = {
   openModal(vm, config) {
     let { zIndex, duration, className, customStyle } = config;
 
-    overlayManager.updateOverlay();
-
     modalStack.push({
       vm,
       config: {
@@ -67,7 +64,6 @@ const overlayManager = {
     if (modalStack.length && topStack.vm.closeOnClickOverlay) { 
       topStack.vm.$emit("click-overlay");
       topStack.vm.close();
-  
     }
   },
 
@@ -118,16 +114,16 @@ const overlayProps = {
 };
 
 function mount(Component, data) {
-  const instance = new Vue({
-    el: document.createElement("div"),
+
+  const instance = new Vue({ 
     props: Component.props,
-    render(h) {
+    render(h) {    
       return h(Component, {
-        props: this.$props,
+        props:this.$props,
         ...data,
       });
     },
-  });
+  }).$mount();
   return instance;
 }
 

+ 84 - 110
src/packages/popup/popup.vue

@@ -1,9 +1,5 @@
 <template>
-  <transition
-    :name="transitionName"
-    @after-enter="$emit('opened')"
-    @after-leave="$emit('closed')"
-  >
+  <transition :name="transitionName" @after-enter="$emit('opened')" @after-leave="$emit('closed')">
     <div
       ref="popupBox"
       v-show="value"
@@ -26,93 +22,95 @@
   </transition>
 </template>
 <script>
-import Vue from "vue";
-import Icon from "../icon/icon.vue";
-import touchMixins from "../../mixins/touch.js";
-import {overlayManager ,overlayProps} from "./overlay/overlay-manager.js";
-import { on, off } from "../../utils/event"; 
-import "../icon/icon.scss";
-
+import Vue from 'vue';
+import Icon from '../icon/icon.vue';
+import touchMixins from '../../mixins/touch.js';
+import { overlayManager, overlayProps } from './overlay/overlay-manager.js';
+import { on, off } from '../../utils/event';
+import '../icon/icon.scss';
 
 const overflowScrollReg = /scroll|auto/i;
+const popupProps = {
+  position: {
+    type: String,
+    default: 'center'
+  },
+
+  transition: String,
+
+  closeable: {
+    type: Boolean,
+    default: false
+  },
+  closeIconPosition: {
+    type: String,
+    default: 'top-right'
+  },
+  closeIcon: {
+    type: String,
+    default: 'cross'
+  },
+
+  closeOnClickOverlay: {
+    type: Boolean,
+    default: true
+  },
+
+  destroyOnClose: {
+    type: Boolean,
+    default: false
+  },
+  getContainer: String,
+  round: {
+    type: Boolean,
+    default: false
+  }
+};
 export default {
-  name: "nut-popup",
+  name: 'nut-popup',
   mixins: [touchMixins],
   components: {
-    icon: Icon,
+    icon: Icon
   },
   props: {
     ...overlayProps,
-    position: {
-      type: String,
-      default: "center",
-    },
-
-    transition: String,
-
-    closeable: {
-      type: Boolean,
-      default: false,
-    },
-    closeIconPosition: {
-      type: String,
-      default: "top-right",
-    },
-    closeIcon: {
-      type: String,
-      default: "cross",
-    },
-
-    closeOnClickOverlay: {
-      type: Boolean,
-      default: true,
-    },
-
-    destroyOnClose: {
-      type: Boolean,
-      default: false,
-    },
-    getContainer: String,
-    round: {
-      type: Boolean,
-      default: false,
-    },
+    ...popupProps
   },
   created() {
-    this.transition
-      ? (this.transitionName = this.transition)
-      : (this.transitionName = `popup-slide-${this.position}`);
+    this.transition ? (this.transitionName = this.transition) : (this.transitionName = `popup-slide-${this.position}`);
   },
   mounted() {
     if (this.value) {
       this.open();
     }
   },
+  beforeDestroy() {
+    this.close();
+  },
   watch: {
     value(val) {
-      const type = val ? "open" : "close";
+      const type = val ? 'open' : 'close';
       this[type]();
     },
     position(val) {
-      val === "center"
-        ? (this.transitionName = "popup-fade")
-        : (this.transitionName = `popup-slide-${this.position}`);
+      val === 'center' ? (this.transitionName = 'popup-fade') : (this.transitionName = `popup-slide-${this.position}`);
     },
-    getContainer: "portal",
-    overlay: "renderOverlay",
+    getContainer: 'portal',
+    overlay: 'renderOverlay'
   },
   data() {
     return {
       showSlot: true,
-      transitionName: "popup-fade-center",
-      overlayInstant: null,
+      transitionName: 'popup-fade-center',
+      overlayInstant: null
     };
   },
   computed: {
     transitionDuration() {
-      return this.duration ? this.duration + "s" : "initial";
-    },
+      return this.duration ? this.duration + 's' : 'initial';
+    }
   },
+
   methods: {
     open() {
       if (this.opened) {
@@ -120,36 +118,30 @@ export default {
       }
 
       this.opened = true;
-      this.$emit("open");
-   
-      const {
-        duration,
-        overlayClass,
-        overlayStyle,
-        lockScroll,
-        closeOnClickOverlay,
-      } = this; 
+      this.$emit('open');
+
+      const { duration, overlayClass, overlayStyle, lockScroll, closeOnClickOverlay } = this;
       const config = {
-        zIndex:this.zIndex ? this.zIndex : overlayManager.zIndex,
+        zIndex: this.zIndex ? this.zIndex : overlayManager.zIndex,
         duration,
         overlayClass,
         overlayStyle,
         lockScroll,
-        closeOnClickOverlay,
+        closeOnClickOverlay
       };
 
       this.renderOverlay(config);
 
       if (this.lockScroll) {
-        on(document, "touchstart", this.touchStart);
-        on(document, "touchmove", this.onTouchMove);
+        on(document, 'touchstart', this.touchStart);
+        on(document, 'touchmove', this.onTouchMove);
 
         if (!overlayManager.lockCount) {
-          document.body.classList.add("nut-overflow-hidden");
+          document.body.classList.add('nut-overflow-hidden');
         }
         overlayManager.lockCount++;
       }
-      
+
       this.$el.style.zIndex = this.zIndex ? this.zIndex + 1 : overlayManager.zIndex;
     },
     renderOverlay(config) {
@@ -165,61 +157,42 @@ export default {
     },
     onTouchMove(event) {
       this.touchMove(event);
-      const el = this.getScroller(event.target, this.$el);
-      const { scrollHeight, offsetHeight, scrollTop } = el;
-
-      if (
-        (this.deltaY > 0 && scrollTop === 0) ||
-        (this.deltaY < 0 && scrollTop + offsetHeight >= scrollHeight)
-      ) {
-        event.preventDefault();
+      const el = this.getScroller(event.target);
+      const { scrollHeight, offsetHeight, scrollTop } = el ? el : this.$el;
+
+      if ((this.deltaY > 0 && scrollTop === 0) || (this.deltaY < 0 && scrollTop + offsetHeight >= scrollHeight)) {
+        //event.preventDefault();
       }
     },
-    getScroller(el, root) {
+    getScroller(el) {
       let node = el;
-      while (
-        node &&
-        node.tagName !== "HTML" &&
-        node.nodeType === 1 &&
-        node !== root
-      ) {
+      while (node && node.tagName !== 'HTML' && node.nodeType === 1) {
         const { overflowY } = window.getComputedStyle(node);
 
         if (overflowScrollReg.test(overflowY)) {
-          if (node.tagName !== "BODY") {
-            return node;
-          }
-          const { overflowY: htmlOverflowY } = window.getComputedStyle(
-            node.parentNode
-          );
-
-          if (overflowScrollReg.test(htmlOverflowY)) {
-            return node;
-          }
+          return node;
         }
 
         node = node.parentNode;
       }
-
-      return root;
     },
     close() {
       if (!this.opened) {
         return;
       }
-      this.$emit('close')
+      this.$emit('close');
       this.opened = false;
       if (this.lockScroll) {
         overlayManager.lockCount--;
-        off(document, "touchstart", this.touchStart);
-        off(document, "touchmove", this.onTouchMove);
+        off(document, 'touchstart', this.touchStart);
+        off(document, 'touchmove', this.onTouchMove);
         if (!overlayManager.lockCount) {
-          document.body.classList.remove("nut-overflow-hidden");
+          document.body.classList.remove('nut-overflow-hidden');
         }
       }
 
       overlayManager.closeOverlay(this);
-      this.$emit("input", false);
+      this.$emit('input', false);
     },
 
     getElement(selector) {
@@ -239,7 +212,8 @@ export default {
       if (container && container !== el.parentNode) {
         container.appendChild(el);
       }
-    },
-  },
+    }
+  }
 };
+export  {popupProps}
 </script>

+ 1 - 0
src/packages/searchbar/searchbar.scss

@@ -8,6 +8,7 @@
     margin-right: 10px;
     background-color: $light-color;
     border-radius: 20px;
+    overflow: hidden;
     form {
       display: flex;
       align-items: center;

+ 9 - 0
src/packages/switch/demo.vue

@@ -56,6 +56,15 @@
         <span slot="title"><nut-switch :active="true" class="my-switch"></nut-switch></span>
       </nut-cell>
     </div>
+        <h4>内嵌文字标签</h4>
+    <div>
+      <nut-cell>
+        <span slot="title"><nut-switch :active="true" label="ON|OFF"></nut-switch></span>
+      </nut-cell>
+           <nut-cell>
+        <span slot="title"><nut-switch :active="false" label="通过|拒绝"></nut-switch></span>
+      </nut-cell>
+    </div>
   </div>
 </template>
 

+ 10 - 2
src/packages/switch/doc.md

@@ -80,7 +80,14 @@ export default {
 >
 </nut-switch>
 ```
-
+## 内嵌文字
+```html
+<nut-switch 
+  :active="true"  
+  :label="开|关"
+>
+</nut-switch>
+```
 
 ## Prop
 
@@ -88,4 +95,5 @@ export default {
 |----- | ----- | ----- | -----
 | active | 开关状态 | Boolean | false
 | size | 尺寸,可选值small/base/large | String | base
-| disabled | 是否禁用 | Boolean | false
+| disabled | 是否禁用 | Boolean | false
+| label | 内嵌文字标签,竖线分开,如ON\|OFF 或 开\|关 | String  | 

+ 38 - 9
src/packages/switch/switch.scss

@@ -1,12 +1,25 @@
 .nut-switch {
   position: relative;
-  display: inline-block;
+  width: auto;
+  display: inline-block !important;
   background: #fff;
   border-radius: 1000px;
   vertical-align: bottom;
   box-sizing: content-box;
   border: 2px $border-style-base $border-color-base;
   transition: all $transition-duration $animation-timing-fun;
+  .nut-switch-label {
+    position:relative;
+    width:auto;
+    left:0;
+    margin-left:22px;
+    display: inline-block !important;
+    padding:0 2px 0 2px  !important;
+    text-align:center !important;
+    color:#999 !important;
+    font-style:normal !important;
+    font-size:12px;
+  }
   .nut-switch-btn {
     position: absolute;
     left: 0;
@@ -15,9 +28,16 @@
     border-radius: 50%;
     box-sizing: border-box;
     transition: all $transition-duration $animation-timing-fun;
+
   }
   &.nut-switch-active {
     border-color: $border-color-active;
+   .nut-switch-label {
+    left:0;
+    margin-left:0px;
+    color:red !important;
+    margin-right:22px;
+   }
     .nut-switch-btn {
       background-color: $primary-color;
     }
@@ -29,42 +49,51 @@
 
 .nut-switch-small {
   height: 14px;
-  width: 32px;
+  min-width: 36px;
+  .nut-switch-label {
+    font-size: 10px;
+    top:-4px;
+    margin-left:-25px;
+  }
   .nut-switch-btn {
     height: 14px;
     width: 14px;
   }
   &.nut-switch-active {
     .nut-switch-btn {
-      left: 18px;
+      left: 100%;
+      margin-left:-15px;
     }
   }
 }
 
 .nut-switch-base {
   height: 20px;
-  width: 46px;
+  min-width: 46px;
   .nut-switch-btn {
     height: 20px;
-    width: 20px;
+    width: 22px;
   }
   &.nut-switch-active {
     .nut-switch-btn {
-      left: 26px;
+      left: 100%;
+      margin-left:-21px;
     }
   }
 }
 
 .nut-switch-large {
   height: 28px;
-  width: 58px;
+  min-width: 58px;
+  font-size: 14px;
   .nut-switch-btn {
     height: 28px;
-    width: 28px;
+    min-width: 28px;
   }
   &.nut-switch-active {
     .nut-switch-btn {
-      left: 30px;
+      left: 100%;
+      margin-left:-28px;
     }
   }
 }

+ 10 - 2
src/packages/switch/switch.vue

@@ -1,6 +1,9 @@
 <template>
   <div class="nut-switch" :class="[{ 'nut-switch-active': isActive }, 'nut-switch-' + size, { 'nut-switch-disabled': disabled }]" @click="toggle">
-    <div class="nut-switch-btn"></div>
+    <div class="nut-switch-btn">
+    </div>
+      <div class="nut-switch-label" v-if="isActive">{{arrLabel[0]}}</div>
+      <div class="nut-switch-label" v-else>{{arrLabel[1]}}</div>
   </div>
 </template>
 <script>
@@ -18,11 +21,16 @@ export default {
     disabled: {
       type: Boolean,
       default: false
+    },
+    label:{
+      type: String,
+      default: ""
     }
   },
   data() {
     return {
-      isActive: false
+      isActive: false,
+      arrLabel : ( this.label||'').split('|')
     };
   },
   created() {

+ 12 - 1
src/packages/tabbar/tabbar.vue

@@ -3,7 +3,7 @@
     <a
       class="tabbar-nav"
       v-for="(value, index) in tabList"
-      :class="[{ curr: index == currIndex }, type]"
+      :class="[{ 'curr': index == currIndex }, type]"
       :key="value.tabTitle"
       v-on:click="switchTabs(value, index)"
       :href="value.href"
@@ -44,15 +44,26 @@ export default {
       tabList: this.tabbarList
     };
   },
+  mounted(){
+    this.initBar();
+  },
   watch: {
     tabbarList: {
       handler(value) {
         this.tabList = value;
+        this.initBar();
       },
       deep: true
     }
   },
   methods: {
+    initBar(){
+      this.tabList.forEach((item,index)=>{
+        if(item.curr){
+            this.currIndex = index;
+        }
+      })
+    },
     switchTabs: function(value, index) {
       this.currIndex = index;
       this.$emit('tab-switch', value, index);

+ 54 - 48
src/packages/textbox/demo.vue

@@ -1,55 +1,61 @@
 <template>
-  <div class="textbox-demo">
-    <!-- <h4>示例</h4> -->
-    <h4>默认用法 支持异步回显数据</h4>
-    <nut-textbox v-model="val"></nut-textbox>
-    <h4>自定义高度:100px</h4>
-    <nut-textbox :txtAreaH="100" :maxNum="300" :value="val"></nut-textbox>
-
-    <h4>自定义提示语</h4>
-    <nut-textbox :placeText="'请填写详细情况请填写详细情况'"></nut-textbox>
-
-    <h4>自定义字数限制</h4>
-    <nut-textbox :maxNum="100"></nut-textbox>
-
-    <h4>限制字数不可超出</h4>
-    <nut-textbox :switchMax="true" :maxNum="10" :txtAreaH="100" textBgColor="#efefef"></nut-textbox>
-
-    <h4>字数超出报错</h4>
-    <nut-textbox :maxNum="10" :txtAreaH="100" @errorFunc="overLength"></nut-textbox>
-
-    <h4>自定义文本框背景色</h4>
-    <nut-textbox :switchMax="true" :maxNum="10" :txtAreaH="100" textBgColor="#feefef"></nut-textbox>
-
-    <h4>不显示字数限制</h4>
-    <nut-textbox :limitShow="false" :maxNum="10"></nut-textbox>
-
-    <h4>输入回调返回文字</h4>
-    <nut-textbox :maxNum="10" txtAreaH="100" @inputFunc="inputText"></nut-textbox>
-  </div>
+    <div class="textbox-demo">
+        <!-- <h4>示例</h4> -->
+        <h4>默认用法 支持异步回显数据</h4>
+         <nut-textbox v-model="val"></nut-textbox>
+        <h4>自定义高度:100px</h4>
+        <nut-textbox :txtAreaH="100" :maxNum="300" v-model="val"></nut-textbox>
+
+        <h4>自定义提示语</h4>
+        <nut-textbox :placeText="'请填写详细情况请填写详细情况'" v-model="val1"></nut-textbox>
+        
+
+        <h4>自定义字数限制</h4>
+        <nut-textbox :maxNum="100" v-model="val2"></nut-textbox>
+        
+
+        <h4>限制字数不可超出</h4>
+        <nut-textbox :switchMax="true" :maxNum="10" :txtAreaH="100" textBgColor="#efefef"></nut-textbox>
+        
+
+        <h4>字数超出报错</h4>
+        <nut-textbox :maxNum="10" :txtAreaH="100"  @errorFunc="overLength" v-model="val1" ></nut-textbox>
+        
+
+        <h4>自定义文本框背景色</h4>
+        <nut-textbox :switchMax="true" :maxNum="10" :txtAreaH="100" textBgColor="#feefef" v-model="val1"></nut-textbox>
+
+        <h4>不显示字数限制</h4>
+        <nut-textbox :limitShow="false" :maxNum="10" v-model="val1" ></nut-textbox>
+       
+        <h4>输入回调返回文字</h4>
+        <nut-textbox  :maxNum="10" txtAreaH="100" @inputFunc="inputText" ></nut-textbox>
+    </div>
 </template>
 
 <script>
 export default {
-  data() {
-    return {
-      val: ''
-    };
-  },
-  methods: {
-    overLength() {
-      alert('字数超出');
+    data(){
+        return{
+            val: '',
+            val1:"",
+            val2:"自定义数据"
+        }
+    },
+    methods:{
+        overLength(){
+            alert("字数超出");
+        },
+        inputText(val){
+           alert(val);
+        }
     },
-    inputText(val) {
-      alert(val);
-    }
-  },
-  mounted() {
-    var that = this;
-    this.val = '初始测试数据';
-    setTimeout(function() {
-      that.val = '异步测试数据123';
-    }, 1000);
-  }
-};
+    mounted(){
+        var that=this;
+        this.val="初始测试数据"
+        setTimeout(function(){
+            that.val="异步测试数据123";
+        },1000)
+        }
+}
 </script>

+ 6 - 4
src/packages/textbox/doc.md

@@ -17,19 +17,19 @@
 ## 自定义提示语
 
 ```html
-<nut-textbox :placeText="'请填写详细情况请填写详细情况'"> </nut-textbox>
+<nut-textbox :placeText="'请填写详细情况请填写详细情况'" v-model="val1"> </nut-textbox>
 ```
 
 ## 自定义字数限制
 
 ```html
-<nut-textbox :maxNum="100"> </nut-textbox>
+<nut-textbox :maxNum="100" v-model="val2"> </nut-textbox>
 ```
 
 ## 限制字数不可超出
 
 ```html
-<nut-textbox :switchMax="true" :maxNum="10" :txtAreaH="2" textBgColor="#efefef">
+<nut-textbox :switchMax="true" :maxNum="10" :txtAreaH="2" textBgColor="#efefef" v-model="val2">
 </nut-textbox>
 ```
 
@@ -66,7 +66,9 @@
 export default {
   data() {
     return {
-      val: ''
+      val: '',
+      val1:'',
+      val2:'自定义数据'
     }
   },
   methods: {

+ 2 - 2
src/packages/textbox/index.js

@@ -1,7 +1,7 @@
 import TextBox from './textbox.vue';
 import './textbox.scss';
 TextBox.install = function(Vue) {
-  Vue.component(TextBox.name, TextBox);
+    Vue.component(TextBox.name, TextBox);
 };
 
-export default TextBox;
+export default TextBox

+ 33 - 33
src/packages/textbox/textbox.scss

@@ -1,34 +1,34 @@
-.nut-textbox {
-  background: #fff;
-  .txt-area {
-    border: 1px solid #ececee;
-    padding: 5px 20px 5px 10px;
-    position: relative;
-    &.num-none {
-      padding: 10px 20px;
+.nut-textbox{
+	background:#fff;
+    .txt-area{
+        border: 1px solid #ececee;
+	    padding: 5px 20px 5px 10px;;
+	    position: relative;
+        &.num-none{
+            padding:10px 20px;
+        }
+        textarea{
+            resize: none;
+		    width: 100%;
+		    border: none;
+		    outline: none;
+		    margin: 0;
+		    padding: 0;
+		    background: transparent;
+            display:block;
+        }
+        span{
+            color: #666;
+		    position: absolute;
+		    right: 10px;
+		    bottom: 5px;
+		    font-size:12px;
+        }
+        &.error{
+        	border:1px solid #e2231a;
+        	span{
+        		color:#e2231a;
+        	}
+        }
     }
-    textarea {
-      resize: none;
-      width: 100%;
-      border: none;
-      outline: none;
-      margin: 0;
-      padding: 0;
-      background: transparent;
-      display: block;
-    }
-    span {
-      color: #666;
-      position: absolute;
-      right: 10px;
-      bottom: 5px;
-      font-size: 12px;
-    }
-    &.error {
-      border: 1px solid #e2231a;
-      span {
-        color: #e2231a;
-      }
-    }
-  }
-}
+}

+ 80 - 77
src/packages/textbox/textbox.vue

@@ -1,87 +1,90 @@
 <template>
-  <div class="nut-textbox">
-    <div class="txt-area" :class="{ error: errorState, 'num-none': limitShow == false }" :style="{ background: textBgColor }">
-      <textarea
-        :placeholder="placeText"
-        :style="{ height: txtAreaHeight + 'px' }"
-        v-model="value"
-        @input="txtIptLength"
-        :switchMax="switchMax"
-        :maxlength="iptMaxlength"
-      ></textarea>
-      <span v-show="limitShow">{{ txtNum }}/{{ maxNum }}</span>
+    <div class="nut-textbox">
+        <div class="txt-area" :class="{'error':errorState,'num-none':limitShow == false}" :style="{background:textBgColor}">
+            <textarea :placeholder="placeText" :style="{height:txtAreaHeight+'px'}"  v-model="currentValue" @input="txtIptLength" :switchMax="switchMax" :maxlength="iptMaxlength"></textarea>
+            <span v-show="limitShow">{{txtNum}}/{{maxNum}}</span>
+        </div>
     </div>
-  </div>
 </template>
 <script>
 export default {
-  name: 'nut-textbox',
-  props: {
-    value: {
-      type: String,
-      default: ''
+    name:'nut-textbox',
+    props: {
+        value: {
+            type: String,
+            default: ""
+        },
+    	maxNum:{
+    		type:[String,Number],
+    		default:50,
+    	},
+    	placeText:{
+    		type:String,
+    		default:'请您在此输入',
+    	},
+    	txtAreaH:{
+    		type:[String,Number],
+    		default:"50",
+    	},
+    	switchMax:{
+    		type:Boolean,
+    		default:false,
+    	},
+        textBgColor:{
+            type:String,
+            default:'#fff'
+        },
+        limitShow:{
+            type:Boolean,
+            default:true,
+        }
     },
-    maxNum: {
-      type: [String, Number],
-      default: 50
+    data() {
+        return {
+           
+            errorState:false,
+            txtNum:0,
+        };
     },
-    placeText: {
-      type: String,
-      default: '请您在此输入'
+    mounted(){
+       
     },
-    txtAreaH: {
-      type: [String, Number],
-      default: '50'
+    computed:{
+        currentValue:{
+            get(){
+                return this.value;
+            },
+            set(val){
+            }
+        },
+        txtAreaHeight:function(){
+           let txtAreaH;
+           txtAreaH = this.txtAreaH;
+                
+           return txtAreaH;
+        },
+        iptMaxlength(){
+        	let maxlength;
+        	if (this.switchMax) {
+        		maxlength = this.maxNum
+        	}
+        	return maxlength
+        },
     },
-    switchMax: {
-      type: Boolean,
-      default: false
-    },
-    textBgColor: {
-      type: String,
-      default: '#fff'
-    },
-    limitShow: {
-      type: Boolean,
-      default: true
-    }
-  },
-  data() {
-    return {
-      errorState: false,
-      txtNum: 0
-    };
-  },
-  computed: {
-    txtAreaHeight: function() {
-      let txtAreaH;
-      txtAreaH = this.txtAreaH;
-
-      return txtAreaH;
-    },
-    iptMaxlength() {
-      let maxlength;
-      if (this.switchMax) {
-        maxlength = this.maxNum;
-      }
-      return maxlength;
-    }
-  },
-  methods: {
-    txtIptLength(event) {
-      const data = event.target.value;
-      console.log(data);
-      const txtLength = data.length;
-      this.txtNum = txtLength;
-      if (txtLength > this.maxNum) {
-        this.errorState = true;
-        this.$emit('errorFunc');
-      } else {
-        this.errorState = false;
-      }
-      this.$emit('inputFunc', data);
-      this.$emit('input', data);
+    methods: {
+        txtIptLength(event){
+            const data = event.target.value
+            const txtLength = data.length;
+            this.txtNum = txtLength;
+            if(txtLength > this.maxNum) {
+                this.errorState = true;
+                this.$emit('errorFunc'); 
+           	}else{
+                this.errorState = false;
+           	}
+            this.$emit('inputFunc',data);
+            this.$emit('input',data);
+        }
     }
-  }
-};
-</script>
+}
+</script>