如何抽象一个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 相关文章推荐
再谈IE中Flash控件的自动激活 ObjectWrap
Mar 09 Javascript
jquery 插件开发方法小结
Oct 23 Javascript
jquery解决图片路径不存在执行替换路径
Feb 06 Javascript
jquery如何把参数列严格转换成数组实现思路
Apr 01 Javascript
使用javascript为网页增加夜间模式
Jan 26 Javascript
JavaScript中实现PHP的打乱数组函数shuffle实例
Oct 11 Javascript
etmvc+jQuery EasyUI+combobox多值操作实现角色授权实例
Nov 09 Javascript
Angular动态绑定样式及改变UI框架样式的方法小结
Sep 03 Javascript
Node4-5静态资源服务器实战以及优化压缩文件实例内容
Aug 29 Javascript
Vue3 的响应式和以前有什么区别,Proxy 无敌?
May 20 Javascript
vue + node如何通过一个Txt文件批量生成MP3并压缩成Zip
Jun 02 Javascript
jQuery实现动态加载瀑布流
Sep 01 jQuery
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通用检测函数集合
2011/02/08 PHP
thinkphp,onethink和thinkox中验证码不显示的解决方法分析
2016/06/06 PHP
thinkphp 字母函数详解T/I/N/D/M/A/R/U
2017/04/03 PHP
不要小看注释掉的JS 引起的安全问题
2008/12/27 Javascript
js获取提交的字符串的字节数
2009/02/09 Javascript
jQuery textarea的长度进行验证
2009/05/06 Javascript
jQuery 学习6 操纵元素显示效果的函数
2010/02/07 Javascript
dojo随手记 gird组件引用
2011/02/24 Javascript
浅谈关于JavaScript的语言特性分析
2013/04/11 Javascript
js校验表单后提交表单的三种方法总结
2014/02/28 Javascript
DOM基础教程之事件类型
2015/01/20 Javascript
深入理解bootstrap框架之第二章整体架构
2016/10/09 Javascript
javascript 实现动态侧边栏实例详解
2016/11/11 Javascript
JavaScript实现创建自定义对象的常用方式总结
2018/07/09 Javascript
vue做移动端适配最佳解决方案(亲测有效)
2018/09/04 Javascript
原生js实现公告滚动效果
2021/01/10 Javascript
深入webpack打包原理及loader和plugin的实现
2020/05/06 Javascript
Vue项目开发常见问题和解决方案总结
2020/09/11 Javascript
axios解决高并发的方法:axios.all()与axios.spread()的操作
2020/11/09 Javascript
Python使用百度API上传文件到百度网盘代码分享
2014/11/08 Python
浅谈python numpy中nonzero()的用法
2018/04/02 Python
用Pycharm实现鼠标滚轮控制字体大小的方法
2019/01/15 Python
使用Python和Prometheus跟踪天气的使用方法
2019/05/06 Python
用Python徒手撸一个股票回测框架搭建【推荐】
2019/08/05 Python
美国汽车性能部件和赛车零件网站:Vivid Racing
2018/03/27 全球购物
Zipadee-Zip襁褓过渡毯:Sleeping Baby
2018/12/30 全球购物
俄罗斯美容和健康网上商店:Созвездие Красоты
2019/07/23 全球购物
演讲稿怎么写
2014/01/07 职场文书
大学生求职工作的自我评价
2014/02/13 职场文书
央视元宵晚会主持串词
2014/03/25 职场文书
城管大队整治方案
2014/05/06 职场文书
保护环境建议书100字
2014/05/13 职场文书
音乐兴趣小组活动总结
2014/07/07 职场文书
会计简历自我评价
2015/03/10 职场文书
使用Canvas绘制一个游戏人物属性图
2022/03/25 Javascript
vue实现省市区联动 element-china-area-data插件
2022/04/22 Vue.js