vue-touch is based on hammer, which is too large for ordinary simple gesture pages!
So I wanted to implement one of the most commonly used gesture taps myself. Following the custom instructions and plug-in documentation, I implemented a v-tap instruction last night and posted this article.
Instructions and plug-ins introduction
Custom instructions and plug-ins are also introduced in the official documentation in a relatively simple and detailed manner, so I won’t go into too much detail.
Let me start by saying that this plug-in uses three APIs. If you don’t understand them, it’s best to read the documentation in advance to avoid confusion in the subsequent code.
Instruction part
1.update(nVal,oVal)
2.acceptStatement
Plug-in part
Vue.use()
Then we need to learn the format of writing Vue plug-ins like writing jQuery plug-ins.
Continue to the official document
MyPlugin.install = function (Vue, options) { // 1. 添加全局方法或属性 Vue.myGlobalMethod = ... // 2. 添加全局资源 Vue.directive('my-directive', {}) // 3. 添加实例方法 Vue.prototype.$myMethod = ... }
Don’t you still understand? Then we can look directly at the author's plug-in code.
;(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) } })()
I deleted all the redundant irrelevant code, and you can find that the format is actually like this, and the rest can be written directly using our own js skills.
PS: Regarding the attribute "isFn:true", I did not find relevant information in the document. I personally think it may be a comment, indicating that this instruction requires an expression of fn (this is the expression of the instruction, see the instruction instance attribute for details) .
Just do it
First, write the outer layer according to the plug-in format.
;(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); } })();
Then write our own custom instructions in our 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) { } }); };
Since only update has parameters to pass and can receive our expression, so I bound the event The processing procedures are all written in the update.
PS: Of course, some friends like to assign all fn to this (here this is a directve instance), and finally bind the event at the bind location. I haven't found the standard for this, and I don't know which one is better to write.
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); }
In update, it is very simple, which is the process of initialization, event binding and assigning values to instances.
The last step is the logical processing of isTap, touchstart, and 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); }
Finally there is a big question, how can we make our expression accept parameters?
<ul> <li v-for="el in list" v-tap="args($index,el,$event)" > {{el.name}}---{{el.age}} </li> </ul>
Then we need to add an attribute acceptStatement:true to our directive (see the document acceptStatement for details)
Summary
Written this v-tap plug-in to share with you some experiences.
1. This in update points to the directive instance, not vm, nor dom
2. Customizable properties and methods can be used in the directive('name',{}) object. The call is self.xxx
3. Enable custom instructions to accept inline statements acceptStatement:true
4. Don’t forget Vue.use(obj) for the final interface
I don’t have v-tap.stop, v-tap.prevent here , v-tap.stop.prevent is used for processing, you can implement it yourself! Also very simple.