如何抽象一个Vue公共组件


Posted in Javascript onOctober 17, 2017

之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子。恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件。

先上 Demo 与 源码。(demo最好在浏览器里以手机模式浏览)

在讲具体实现前,我想先分享下自己认为的理想的公用组件是什么样的:

1. 黑盒性,即除了你自己以外,其他的开发者在快速阅读使用文档之后可以立刻上手,而不用关心你的内部实现;

2. 独立性,即做好解耦,不与父组件有过多关联;

3 自定义性,适当地暴露一些输入接口或者方法给外部用于自定义,同时也要设置好这些属性在外部未输入时的默认值。 

下面我们先以黑盒的方式看看 demo 中数字键盘组件是如何调用的(已省略非关键部分代码)。

App.vue

<template>
......
  <keyboard @submit-event='handleSubmit' @change-event='handleChange'></keyboard>
</template>
<script>
import keyboard from 'Keyboard.vue';
export default {
  data() {
    return {
      value: ''
    };
  },
  methods: {
    handleChange(value, currentValue) {
      console.log(value, currentValue);
      this.value = value;
    },
    handleSubmit() {
      console.log('submit: ' + this.value);
    }
  }
}
</script>

如上,最基本的调用就完成了。效果如下:

如何抽象一个Vue公共组件

接着,点击 1-6 与“确定”。如果如下:

如何抽象一个Vue公共组件

可以看到数字键盘已经如我们预期工作了,接下来分析下该数字键盘组件所有的输入项。

@change-event:该事件为自定义事件,父组件通过 v-on 注册监听,子组件内部通过 $emit 进行触发(更多自定义事件相关内容请参考:Vue官方教程)。

每一次点击数字按键以及退格键均会触发该事件,其传递两个参数:value,累积点击的字符组合;currentValue,当前点击的字符。父组件通过 handleChange 方法接收该事件的回调内容。

@submit-event:当点击“确定”键即会触发该事件,其不传递参数,只是告诉父组件“我的确定按钮被点击了,你要做什么操作自己看着办吧,之前点击的数字已经通过 change-event 传给你了”。父组件通过 handleSubmit 方法接收回调。

如果只写这两个方法未免也太没诚意了,我还根据一些场景编写了以下几个自定义属性。

max:最大输入长度,超过的部分将不会触发 change-event 事件,默认无限制。

<keyboard max='6'></keyboard>

sp-key:自定义的特殊字符,如身份证输入时的“X”,会添加到左下角空白格,默认无。

<keyboard sp-key='X'></keyboard>

如何抽象一个Vue公共组件

random:是否打乱数字顺序,一些有关银行账户或密码的输入经常会见到这种场景,默认 false。

<keyboard random='true'></keyboard>

如何抽象一个Vue公共组件

从上面的几个自定义属性与事件,我们大概知道了父组件是如何向子组件传值以及监听子组件的变化,但父组件该如何直接调用子组件内部的函数呢?我们看下面这个场景。

数字键盘上的键盘图标,点击之后会将数字键盘收起隐藏。组件内部拥有一个方法 keyboardToggle(true|false) 来控制键盘的弹起和收回,那么如果在组件外部也想调用这个方法呢?比如当父组件中的 input 获取到焦点时。

可以通过 Vue 中的 ref 属性来获取到键盘的组件引用,从而调用其内部的方法,如下:

$refs.[refName].keyboardToggle(true|false)

<template>
  <input type='text' @focus='handleShowKeyboard($event)' />
  <keyboard ref='kbref'></keyboard>
</template>
<script>
import keyboard from 'Keyboard';
export default {
  //...
  methods: {
    handleShowKeyboard(e) {
      e && e.preventDefault();
      this.$refs.kbref.keyboardToggle(true);
    }
  }
}
</script>

以上面这种形式便可以在父组件上下文中调用子组件内的方法。

$refs.[refName].handleInit()

数字键盘组件内部的初始化方法,用于重新渲染组件。若 random 属性为 true,则数字键会刷新随机排列。

$refs.[refName].handleClear()

清除之前输入的字符组合,并触发 change-event 且返回空字符串。

上面分享了这个组件所有对外的属性与事件,可以发现我们并未看过该组件内部的一行代码,但已经可以完整的使用它了,下面来聊聊内部实现。

首先来看看布局,我将键盘分为左右两部分,右边部分不用多说,左边的部分是将一个键位数组通过 v-for 循环生成。

如何抽象一个Vue公共组件

那么是如何让 0 和 9 之间空出一格呢,下面看下初始化键盘组件的方法。

keyboard.vue

handleInit()

<template>
  <div>
    <div class='kb-left'>
      <div class='kb-item' v-for='item in keyArr'>{{item}}</div>
      <div class='kb-item kb-toggle'></div> //键盘图标
    </div>
    <div class='kb-right'>
      //...    
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      baseArr: []
    }
  },
  computed: {
    keyArr() {
      this.handleInit();
      return this.baseArr;
    }
  },
  methods: {
    handleInit() {
      this.baseArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
      this.baseArr.splice(this.baseArr.length - 1, 0, '');
    }
  }
}
</script>

即在键位数组倒数第二位插入一个空字符,然后循环生成按键。下面看下自定义参数是如何生效的。

sp-key

<script>
export default {
  props: ['spKey'],
  data() {
    return {
      baseArr: []
    }
  },
  //....
  methods: {
    handleInit() {
      let spKey = this.spKey;
      this.baseArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];



 this.baseArr.splice(this.baseArr.length - 1, 0, spKey);
    }
  }
}
</script>

在组件内部通过 props 属性接收父组件传递的 spKey,之后就可在组件内的属性和方法中通过 this.spKey 进行访问。首先判断 spKey 值是否有效,并代替空字符插入键位数组倒数第二项。

random

<script>
export default {
  props: ['spKey', 'random'],
  data() {
    return {
      baseArr: []
    }
  },
  //....
  methods: {
    handleInit() {
      let spKey = this.spKey;
      this.baseArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];

    if (this.random && this.random != 'false') {
      
this.baseArr.sort(function() {
      
 return Math.random() - Math.random();
    

});
      }

      this.baseArr.splice(this.baseArr.length - 1, 0, spKey);
    }
  }
}
</script>

将键位打乱顺序其实也很简单,只要通过数组的 sort 方法。sort 方法可以接收一个函数作为参数,若函数返回正数则交换前后两项的位置,若函数返回负数则不作交换。所以将两个随机数相减的结果返回,即可将键位数组随机排序。

下面看看在组件内部是如何触发 change-event 的。

handleInput()

<template>
  <div>
    <div class='kb-left'>
      <div @click='handleInput(item)' class='kb-item' v-for='item in keyArr'>{{item}}</div>
      <div class='kb-item kb-toggle'></div> //键盘图标
    </div>
    //...
  </div>
</template>
<script>
export default {
  data() {
    return {
      inputStr: ''
    }
  },
  //...
  methods: {
    handleInput(value) {
      this.inputStr += value;
      this.$emit('change-event', this.inputStr, value);
    }
  }
}
</script>

增加了 max 属性后修改方法如下:

handleInput(value) {
  let max = Number(this.max);
  if (!isNaN(max) && this.inputStr.length+1 > max) {
    return;
  }

  this.inputStr += value;
  this.$emit('change-event', this.inputStr, value);
}

最后看看退格删除是如何实现的。

handleDelete()

handleDelete() {
  let str = this.inputStr;
 if (!str.length) return;

  this.inputStr = str.substring(0, str.length - 1);
  this.$emit('change-event', this.inputStr);
}

上面的例子都是些核心代码的片段,并且其他辅助函数并未列出,想查看完整的代码请看源码。

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用CSS样式position:fixed水平滚动的方法
Feb 19 Javascript
jQuery.each使用详解
Jul 07 Javascript
AngularJS的一些基本样式初窥
Jul 27 Javascript
jquery实现的Accordion折叠面板效果代码
Sep 02 Javascript
JS在onclientclick里如何控制onclick的执行
May 30 Javascript
jQuery实现的自动加载页面功能示例
Sep 04 Javascript
easyUI实现类似搜索框关键词自动提示功能示例代码
Dec 27 Javascript
weex里Vuex state使用storage持久化详解
Sep 09 Javascript
JS删除数组里的某个元素方法
Feb 03 Javascript
JS实现监控微信小程序的原理
Jun 15 Javascript
Angular+Ionic使用queryParams实现跳转页传值的方法
Sep 05 Javascript
Vue全家桶入门基础教程
May 14 Vue.js
vue实现图书管理demo详解
Oct 17 #Javascript
基于Vue实现图书管理功能
Oct 17 #Javascript
Vue.js简易安装和快速入门(第二课)
Oct 17 #Javascript
什么是Vue.js框架 为什么选择它?
Oct 17 #Javascript
node使用Koa2搭建web项目的方法
Oct 17 #Javascript
Node 自动化部署的方法
Oct 17 #Javascript
利用JS实现scroll自定义滚动效果详解
Oct 17 #Javascript
You might like
php使用cookie显示用户上次访问网站日期的方法
2015/01/26 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
你可能不再需要JQUERY
2021/03/09 Javascript
一个js实现的所谓的滑动门
2007/05/23 Javascript
自己做的模拟模态对话框实现代码
2012/05/23 Javascript
javascript自动生成包含数字与字符的随机字符串
2015/02/09 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
关于JavaScript作用域你想知道的一切
2016/02/04 Javascript
理解javascript正则表达式
2016/03/08 Javascript
浅谈在js传递参数中含加号(+)的处理方式
2016/10/11 Javascript
Javascript 获取鼠标当前的位置实现方法
2016/10/27 Javascript
form+iframe解决跨域上传文件的方法
2016/11/18 Javascript
EasyUI修改DateBox和DateTimeBox的默认日期格式示例
2017/01/18 Javascript
详谈js使用in和hasOwnProperty获取对象属性的区别
2017/04/25 Javascript
JS实现上传图片的三种方法并实现预览图片功能
2017/07/14 Javascript
javascript回调函数详解
2018/02/06 Javascript
JS改变页面颜色源码分享
2018/02/24 Javascript
vue父组件向子组件传递多个数据的实例
2018/03/01 Javascript
JS实现十分钟倒计时代码实例
2018/10/18 Javascript
js实现固定区域内的不重叠随机圆
2019/10/24 Javascript
d3.js实现图形拖拽
2019/12/19 Javascript
[13:21]DOTA2国际邀请赛采访专栏:RSnake战队国士无双,Fnatic.Fly
2013/08/06 DOTA
python中偏函数partial用法实例分析
2015/07/08 Python
Python从列表推导到zip()函数的5种技巧总结
2019/10/23 Python
解决Numpy中sum函数求和结果维度的问题
2019/12/06 Python
python3 中使用urllib问题以及urllib详解
2020/08/03 Python
Html5新标签解释及用法
2012/02/17 HTML / CSS
新西兰领先的鞋类和靴子网上商城:Merchant 1948
2017/09/08 全球购物
美国职棒大联盟官方网上商店:MLBShop.com
2017/11/12 全球购物
来自世界各地的饮料:Flavourly
2019/05/06 全球购物
西班牙用户之间买卖视频游戏的平台:Wakkap
2020/03/21 全球购物
2014年两会学习心得范例
2014/03/17 职场文书
禁烟标语大全
2014/06/11 职场文书
2015年公务员个人工作总结
2015/04/24 职场文书
Golang中interface{}转为数组的操作
2021/04/30 Golang
Goland使用Go Modules创建/管理项目的操作
2021/05/06 Golang