一篇知乎的故事 - javascript技术贴
前言
本文的发表源于知乎的一篇文章。文章链接如下:如果你想靠前端技术还房贷,你不能连这个都不会。
前提
1. 本文是一个vue的小组件功能,你需要有vue的经验,并且了解vue的组件。
2. 本文会贴出一个盗版的jQuery.queue函数,这个函数是之前读jq源码自己写的,就是偷得jq,比不上jq强大,但是基本功能还是有的。
3. 本文不适合新手。
切入正文
上面是问题,我们来解读一下需求:
1. 首先要有一个模块,这个模块包括一个input,两个button
2. 模块实现了点击 A,发送urlA请求,并将input值改为请求返回的值,点击B,雷同
3. 用户依次点击A、B,input首先需要改为urlA请求返回的值,再改为urlB返回的值。也就类似于同步请求。
代码如下:
<div id="app"> <my-component></my-component> </div> <template id="tpl"> <div> <input type="text" v-model="inputData" readonly="readonly"> <p> <button @click="request1">按钮A</button> <button @click="request2">按钮B</button> </p> </div> </template> <script src="https://unpkg.com/vue/dist/vue.js"></script> // resource.min.js 自己下载的 <script type="text/javascript" src="./resource.min.js"></script> <script> Vue.use(VueResource) new Vue({ el: '#app', components: { 'my-component': { template: '#tpl', data: function () { return { inputData: '默认的', ajax2: null } }, methods: { request1: function () { var url = '我的测试地址:睡眠2秒再返回值' this.$http.get(url).then(function(res) { this.inputData = res.data this.ajax2() }) }, request2: function () { this.ajax2 = function () { var url = '我的测试地址:睡眠1秒返回值' this.$http.get(url).then(function(res) { this.inputData = res.data }) } }, }, } } }) </script>
我定义了一个vue实例,在#app元素内有效。定义个组件,给这个组件一个inputData属性存储input框中的数据,定义一个ajax2属性存储点击B按钮时的发起请求的函数。我们在点击A后返回值后,调用ajax2这个方法,这样就实现了上面的需求,当然仅仅是实现了上面的需求而已,并且代码看上去很难看,因为我们为了实现这个功能不得不在模型上加了个ajax2这个很鸡肋的中间量,为了让代码更好看一些,功能更强一些,不防试一试用队列来解决。
队列的作用
我们不仅要实现上面这个简单的例子,我们需要实现的效果更强壮:
1. 连续交替点击A、B按钮,将返回值有顺序的显示到input上面
2. 每一次点击都会产生一个ajax请求,但是不会立刻发起,会根据点击顺序依次请求。
3. 利用一个队列对象来实现,使代码变得更简洁更美观。
代码如下:
<div id="app"> <my-component :q="q"></my-component> </div> <template id="tpl"> <div> <input type="text" v-model="inputData" readonly="readonly"> <p> <button @click="request('测试地址1:睡眠2秒')">按钮A</button> <button @click="request('测试地址2:睡眠1秒')">按钮B</button> </p> </div> </template> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script type="text/javascript" src="./vue-resource.min.js"></script> <script type="text/javascript" src="http://git.oschina.net/xuazheng/myJquery/raw/master/queue/queue.js?dir=0&filepath=queue%2Fqueue.js&oid=b23c3bf7212ff41aad350bdb505a1afc59929ce6&sha=d0298a8907c9ed1cf25c176807fadbcd14c3e571"></script> <script type="text/javascript"> Vue.use(VueResource) new Vue({ el: '#app', data: { q: Queue() }, components: { 'my-component': { template: '#tpl', data: function () { return { inputData: '默认的' } }, methods: { request: function (url) { this.q.queue('fx', function (next){ this.$http.get(url).then(function(res) { this.inputData = res.data next() }) }.bind(this)) } }, props: ['q'] }, } }) </script>
引入了我的queue,在vue实例上,创建一个q属性存储queue对象并传递给子组件。在子组件中,我们每次点击一个按钮,都会将一个ajax请求的函数添加到fx队列中,在jquery中,fx类型的队列存储着动画函数,可以处理异步函数队列的有序执行。不传递这个值会默认fx类型,所以也可以直接在queue方法中传递一个方法就行。
队列的代码如下:
;function Queue() { // 数据缓存对象 var cache = {}; var queueList = { // type默认是fx,是动画队列 queue: function(type,data) { var args = arguments; //没有参数直接返回 if(!args.length){ return; } var q = null; // 只有一个参数并且是个函数 if(args.length == 1 && typeof type === 'function') { data = type; type = 'fx'; } q = cache[type] || []; // 添加缓存 if( data instanceof Array) { q = data; }else { q.push(data) } cache[type] = q; //如果是动画队列并且没有开始的动画,执行第一个动画函数 if(type == 'fx' && q.toString().indexOf('inprogress') === -1) { queueList.dequeue() } return q; }, dequeue: function(type) { var fn, queue; type = type || 'fx'; queue = cache[type]; if(queue.length == 0 ) { return; } fn = queue.shift(); if( fn === 'inprogress' ) { fn = queue.shift(); } if( fn ) { if(type === 'fx') { queue.unshift('inprogress'); } fn.call(null,function() { queueList.dequeue(type); }) } }, // 延迟使用setTimeout来实现 delay: function(type,timeout) { if(!type) { return; } if(arguments.length == 1) { timeout = type; type = 'fx'; } if(typeof timeout == 'number') { var q = cache[type]; if(!q) { q = cache[type] = [_delay]; }else { q.push(_delay) } } function _delay() { setTimeout(queueList.dequeue, timeout); } return this; }, get: function(type) { type = type || 'fx'; return cache[type]; } } return queueList; }
这个就不解释了,比起jquery源码,这个代码就显得很简单,jquery中做了大量的处理,然而博主并没有那么厉害,只能简单的写了这点。有js基础的应该看得懂,如果想学jq源码,推荐 艾伦 Aaron 的博客园。