如何抽象一个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 相关文章推荐
每天一篇javascript学习小结(Date对象)
Nov 13 Javascript
javascript的replace方法结合正则使用实例总结
Jun 16 Javascript
AngularJS ng-bind-template 指令详解
Jul 30 Javascript
纯JS实现表单验证实例
Dec 24 Javascript
Angular.JS去掉访问路径URL中的#号详解
Mar 30 Javascript
Angular 4.x 路由快速入门学习
May 03 Javascript
js 原生判断内容区域是否滚动到底部的实例代码
Nov 15 Javascript
vue axios登录请求拦截器
Apr 02 Javascript
详解ES6系列之私有变量的实现
Nov 21 Javascript
微信小程序实现图片翻转效果的实例代码
Sep 20 Javascript
vue 项目中当访问路由不存在的时候默认访问404页面操作
Aug 31 Javascript
创建与框架无关的JavaScript插件
Dec 01 Javascript
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 字符串操作入门教程
2006/12/06 PHP
PHP实现的浏览器检查类
2016/04/11 PHP
addRule在firefox下的兼容写法
2006/11/30 Javascript
基于jQuery制作迷你背词汇工具
2010/07/27 Javascript
纯js网页画板(Graphics)类简介及实现代码
2012/12/24 Javascript
jQuery的显示和隐藏方法与css隐藏的样式对比
2013/10/18 Javascript
JavaScript function 的 length 属性使用介绍
2014/09/15 Javascript
jQuery实现仿腾讯视频列表分页效果的方法
2015/08/07 Javascript
javascript类型系统——undefined和null全面了解
2016/07/13 Javascript
vue params、query传参使用详解
2017/09/12 Javascript
详解在vue-cli中引用jQuery、bootstrap以及使用sass、less编写css
2017/11/08 jQuery
vue js秒转天数小时分钟秒的实例代码
2018/08/08 Javascript
详解Python文本操作相关模块
2017/06/22 Python
python添加模块搜索路径方法
2017/09/11 Python
python实现京东秒杀功能
2018/07/30 Python
解决python3捕获cx_oracle抛出的异常错误问题
2018/10/18 Python
Python中logging实例讲解
2019/01/17 Python
matplotlib实现区域颜色填充
2019/03/18 Python
Python Django中间件,中间件函数,全局异常处理操作示例
2019/11/08 Python
python3用PyPDF2解析pdf文件,用正则匹配数据方式
2020/05/12 Python
django和flask哪个值得研究学习
2020/07/31 Python
Django websocket原理及功能实现代码
2020/11/14 Python
Python中return函数返回值实例用法
2020/11/19 Python
Python爬虫爬取微博热搜保存为 Markdown 文件的源码
2021/02/22 Python
美体小铺瑞典官方网站:The Body Shop瑞典
2018/01/27 全球购物
印度第一网上礼品店:IGP.com
2020/02/06 全球购物
写自荐信有哪些不宜?
2013/10/17 职场文书
2014年幼儿园元旦活动方案
2014/02/13 职场文书
财务管理职业生涯规划书
2014/02/26 职场文书
北体毕业生求职信
2014/02/28 职场文书
勤奋学习演讲稿
2014/05/10 职场文书
幼儿教师自我剖析材料
2014/09/29 职场文书
2014年生产管理工作总结
2014/12/23 职场文书
三十年同学聚会感言
2015/07/30 职场文书
旅游安全责任协议书
2016/03/22 职场文书
Python爬虫之爬取最新更新的小说网站
2021/05/06 Python