vue自定义指令实现v-tap插件


Posted in Javascript onNovember 03, 2016

放弃jQuery,拥抱MVVM,拥抱组件吧!

vue-touch基于hammer,对于普通简单手势的页面来说过于庞大!
于是想自己实现一个最常用的手势tap。顺着自定义指令和插件文档,昨晚实现了一个v-tap指令,丢出这篇干货。

指令与插件介绍
自定义指令和插件官方文档中也介绍比较简单详细,就不过多介绍。
我先说下本插件就用了三个API,如果大家不了解最好先事先看下文档避免后面的代码看的迷糊。

指令部分
1.update(nVal,oVal)
2.acceptStatement

插件部分
Vue.use()

接着我们需要像写jQuery插件一样学习写Vue插件的格式。

继续官方文档

MyPlugin.install = function (Vue, options) {
 // 1. 添加全局方法或属性
 Vue.myGlobalMethod = ...
 // 2. 添加全局资源
 Vue.directive('my-directive', {})
 // 3. 添加实例方法
 Vue.prototype.$myMethod = ...
}

是不是看的还不太明白?那我们可以直接看作者的插件代码。

;(function () {

 var vueTouch = {}

 vueTouch.install = function (Vue) {

 Vue.directive('touch', {

  isFn: true,
  acceptStatement: true,

  bind: function () {

  },

  update: function (fn) {

  },

  unbind: function () {

  }
 })
 }

 if (typeof exports == "object") {
 module.exports = vueTouch
 } else if (typeof define == "function" && define.amd) {
 define([], function(){ return vueTouch })
 } else if (window.Vue) {
 window.VueTouch = vueTouch
 Vue.use(vueTouch)
 }

})()

我把多余无关代码都删除了,可以发现其实格式就是如此,剩下的就是利用我们自己js的功底直接编写即可。
PS:关于 isFn:true 这个属性,我在文档中没有查到相关信息,个人认为可能是一种注释,代表这个指令是需要fn的expression(这个是指令的表达式,详见指令实例属性)。

Just do it

首先,按照插件格式先写好外层。

;(function() {
 var vueTap = {};
 vueTap.install = function(Vue) {

 };

 if (typeof exports == "object") {
  module.exports = vueTap;
 } else if (typeof define == "function" && define.amd) {
  define([], function(){ return vueTap })
 } else if (window.Vue) {
  window.vueTap = vueTap;
  Vue.use(vueTap);
 }

})();

接着在我们的 vueTap.install 里写我们自己的自定义指令

Vue.directive('tap', {
  isFn : true,
  bind : function() {

  },
  update : function(fn) {

  },
  unbind : function() {},
  isTap : function() {
   //判断是否为tap
  },
  touchstart : function(e,self) {

  },
  touchend : function(e,self) {

  }
 });
};

由于只有update才有参数可传,可以接收到我们expression,于是我把事件绑定处理过程都写在了update里。

PS: 当然也有小伙伴喜欢在这把fn都赋予在this(这里的this是directve实例)上,最后在bind的地方绑定事件。这个我并没有找到规范,还不知道写哪比较好。

update : function(fn) {
 var self = this; //存下this,方便以后用
  //在directive上绑定的属性和方法
  //都可通过self.xxx self.touchstart()获取
  self.tapObj = {}; //初始化我们的tap对象

 if(typeof fn !== 'function') {
 //你别给我搞事!
  return console.error('The param of directive "v-tap" must be a function!');
 }

 self.handler = function(e) { //给当前directive存个handler方便之后调用
  e.tapObj = self.tapObj; 
  //把我们的tap对象赋值给原生event对象上,方便回调里获取参数
  fn.call(self,e);
 };

 //把我们的start和end剥离出来,写在directive上
 //由于只有tap事件,所以我们在move过程就不需要做处理
 this.el.addEventListener('touchstart',function(e) {
  self.touchstart(e,self);
 },false);

 this.el.addEventListener('touchend',function(e) {
  self.touchend(e,self,fn);
 },false);

}

在update很简单,就是一些初始化,事件绑定和给实例赋值的过程。
最后就是isTap,touchstart,touchend的逻辑处理。

isTap : function() {
 var tapObj = this.tapObj;
 return this.time < 150 && Math.abs(tapObj.distanceX) < 2 && Math.abs(tapObj.distanceY) < 2;
},
touchstart : function(e,self) {
 var touches = e.touches[0];
 var tapObj = self.tapObj;
 tapObj.pageX = touches.pageX;
 tapObj.pageY = touches.pageY;
 tapObj.clientX = touches.clientX;
 tapObj.clientY = touches.clientY;
 self.time = +new Date();
},
touchend : function(e,self) {
 var touches = e.changedTouches[0];
 var tapObj = self.tapObj;
 self.time = +new Date() - self.time;
 tapObj.distanceX = tapObj.pageX - touches.pageX;
 tapObj.distanceY = tapObj.pageY - touches.pageY;

 if (self.isTap(tapObj))
  self.handler(e);
}

最后有个大问题,如何能让我们的expression可接受传参?

<ul>
 <li v-for="el in list"
  v-tap="args($index,el,$event)"
   >
  {{el.name}}---{{el.age}}
 </li>
</ul>

那就要在我们的directive上加一个属性acceptStatement:true(详见文档acceptStatement)

总结
写了这个v-tap插件几个心得分享给大家。
1.在update里的this指向是directive实例,而不是vm,也不是dom
2.在directive('name',{}) 对象里可自定义属性和方法。调用就是self.xxx
3.开启自定义指令接受内联语句 acceptStatement:true
4.最后的接口别忘了 Vue.use(obj)
我这里没有对v-tap.stop, v-tap.prevent,v-tap.stop.prevent做处理,大家可以自己实现!也灰常简单。
(我之后会对v-tap进行补充)

最后丢出github地址: https://github.com/MeCKodo/vue-tap

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

Javascript 相关文章推荐
10个新的最有前途的JavaScript框架
Mar 12 Javascript
JS通过相同的name进行表格求和代码
Aug 18 Javascript
非html5实现js版弹球游戏示例代码
Sep 22 Javascript
js实现浏览器窗口大小被改变时触发事件的方法
Feb 02 Javascript
第一次接触神奇的Bootstrap网格系统
Jul 27 Javascript
如何使用Bootstrap 按钮实例详解
Mar 29 Javascript
简单谈谈关于 npm 5.0 的新坑
Jun 08 Javascript
Node.js 基础教程之全局对象
Aug 06 Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
Dec 28 Javascript
微信用户访问小程序的登录过程详解
Sep 20 Javascript
JavaScript基于用户照片姓名生成海报
May 29 Javascript
Vuex实现购物车小功能
Aug 17 Javascript
angular ngClick阻止冒泡使用默认行为的方法
Nov 03 #Javascript
vue.js指令v-for使用及索引获取
Nov 03 #Javascript
vue.js初学入门教程(1)
Nov 03 #Javascript
把json格式的字符串转换成javascript对象或数组的方法总结
Nov 03 #Javascript
AngularJS出现$http异步后台无法获取请求参数问题的解决方法
Nov 03 #Javascript
Centos7 中安装 Node.js v4.4.4
Nov 03 #Javascript
[原创]javascript typeof id==='string'?document.getElementById(id):id解释
Nov 02 #Javascript
You might like
多重?l件?合查?(一)
2006/10/09 PHP
PHPEXCEL 使用小记
2013/01/06 PHP
PHP输出时间差函数代码
2013/01/28 PHP
PHP实现全角字符转为半角方法汇总
2015/07/09 PHP
PHP6连接SQLServer2005的三部曲
2016/04/15 PHP
Yii 2.0如何使用页面缓存方法示例
2017/05/23 PHP
PHP下 Mongodb 连接远程数据库的实例代码
2017/08/30 PHP
PHP设计模式之单例模式定义与用法分析
2019/03/26 PHP
用javascript实现分割提取页面所需内容
2007/05/09 Javascript
JS延迟加载(setTimeout) JS最后加载
2010/07/15 Javascript
中文路径导致unitpngfix.js不正常的解决方法
2013/06/26 Javascript
JavaScript实现列出数组中最长的连续数
2014/12/29 Javascript
jQuery过滤选择器详解
2015/01/13 Javascript
Node.js开发者必须了解的4个JS要点
2016/02/21 Javascript
一个仿微博登陆邮箱提示框js开发案例
2016/07/28 Javascript
[原创]JS基于FileSaver.js插件实现文件保存功能示例
2016/12/08 Javascript
js实现适配不同的屏幕大小
2017/04/10 Javascript
基于vue2框架的机器人自动回复mini-project实例代码
2017/06/13 Javascript
vue用addRoutes实现动态路由的示例
2017/09/15 Javascript
JavaScript实现简单动态进度条效果
2018/04/06 Javascript
vue通过数据过滤实现表格合并
2020/11/30 Javascript
p5.js临摹动态图形的方法
2019/10/23 Javascript
leaflet加载geojson叠加显示功能代码
2020/02/21 Javascript
Vue实现移动端拖拽交换位置
2020/07/29 Javascript
python实现数通设备tftp备份配置文件示例
2014/04/02 Python
使用Python读写及压缩和解压缩文件的示例
2016/07/08 Python
python十进制和二进制的转换方法(含浮点数)
2018/07/07 Python
实例讲解Python中整数的最大值输出
2019/03/17 Python
pytorch 实现模型不同层设置不同的学习率方式
2020/01/06 Python
Python如何使用bokeh包和geojson数据绘制地图
2020/03/21 Python
基于SpringBoot构造器注入循环依赖及解决方式
2020/04/26 Python
Python调用shell cmd方法代码示例解析
2020/06/18 Python
利用CSS3的3D效果制作正方体
2020/03/10 HTML / CSS
Carolina Lemke Berlin澳大利亚官网:时尚太阳镜品牌
2019/09/17 全球购物
节约用水倡议书
2014/04/16 职场文书
《李广射虎》教学反思
2014/04/27 职场文书