脚本宝典收集整理的这篇文章主要介绍了

Vue 进阶系列(二)之插件原理及实现

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。
<p><code></p> <p>(关注福利,关注本公众号回复[资料]领取优质前端视频,包括<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>、<a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a>、Node源码和实战、面试指导)<br /><span class="img-wrap"><img data-src="/img/remote/1460000016890954?w=1325&amp;h=897" src="/img/remote/1460000016890954?w=1325&amp;h=897" alt="" title="" style="cursor: pointer; display: inline;"></span></p> <p><a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>进阶系列汇总如下,欢迎阅读,欢迎加高级前端进阶群一起学习(文末)。</p> <p><a href="https://juejin.im/post/5bce6a26e51d4579e9711f1d" rel="nofollow noreferrer" target="_blank">Vue 进阶系列(一)之响应式原理及实现</a> </p> <p><a href="https://juejin.im/post/5bd8fa04e51d45168b64f936" rel="nofollow noreferrer" target="_blank">Vue 进阶系列(二)之插件原理及实现</a></p> <p><a href="https://juejin.im/post/5be2f0ae6fb9a049fa0f3dd2" rel="nofollow noreferrer" target="_blank">Vue 进阶系列(三)之Render函数原理及实现</a></p> <h3 id="articleHeader0">使用方法</h3> <p>插件的详细使用方法详情看<a href="http://www.js-code.com/tag/vue" title="浏览关于“Vue”的文章" target="_blank" class="tag_link">Vue</a>官网</p> <blockquote><p><a href="https://cn.vuejs.org/v2/guide/plugins.html" rel="nofollow noreferrer" target="_blank">Vue官网之插件Plugins</a></p></blockquote> <p>概括出来就是</p> <ul> <li>1、通过<code>Vue.use(MyPlugin)</code>使用,本质上是调用<code>MyPlugin.install(Vue)</code> </li> <li>2、使用插件必须在<code>new Vue()</code>启动应用之前完成,实例化之前就要配置好。</li> <li>3、如果使用<code>Vue.use</code>多次注册相同插件,那只会注册成功一次。</li> </ul> <h3 id="articleHeader1">源码解读</h3> <p><code>Vue.use</code>源码如下</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="Vue.use = function (plugin) { // 忽略已注册插件 if (plugin.installed) { return } // 集合转数组,并去除第一个参数 var args = toArray(arguments, 1); // 把this(即Vue)添加到数组的第一个参数中 args.unshift(this); // 调用install方法 if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args); } else if (typeof plugin === 'function') { plugin.apply(null, args); } // 注册成功 plugin.installed = true; return this; };" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="js">Vue.use = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">plugin</span>) </span>{ <span class="hljs-comment">// 忽略已注册插件</span> <span class="hljs-keyword">if</span> (plugin.installed) { <span class="hljs-keyword">return</span> } <span class="hljs-comment">// 集合转<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="浏览关于“数组”的文章" target="_blank" class="tag_link">数组</a>,并去除第一个参数</span> <span class="hljs-keyword">var</span> args = to<a href="http://www.js-code.com/tag/array" title="浏览关于“Array”的文章" target="_blank" class="tag_link">Array</a>(<span class="hljs-built_in">arguments</span>, <span class="hljs-number">1</span>); <span class="hljs-comment">// 把<a href="http://www.js-code.com/tag/this" title="浏览关于“this”的文章" target="_blank" class="tag_link">this</a>(即Vue)添加到数组的第一个参数中</span> args.unshift(<span class="hljs-keyword">this</span>); <span class="hljs-comment">// 调用install方法</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> plugin.install === <span class="hljs-string">'function'</span>) { plugin.install.apply(plugin, args); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> plugin === <span class="hljs-string">'function'</span>) { plugin.apply(<span class="hljs-literal">null</span>, args); } <span class="hljs-comment">// 注册成功</span> plugin.installed = <span class="hljs-literal">true</span>; <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; };</code></pre> <p><code>Vue.use</code>接受一个对象参数<code>plugin</code>,首先判断是否已注册,如果多次注册相同插件那么只会注册成功一次,在注册成功后设置<code>plugin.installed = true</code>。</p> <p>然后执行<code>to<a href="http://www.js-code.com/tag/array" title="Array" target="_blank">Array</a>(arguments, 1)</code>方法,<code>arguments</code>是一个表示所有参数的类<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a>对象,需要转换成<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a>之后才能使用数组的方法。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="function toArray (list, start) { start = start || 0; var i = list.length - start; var ret = new Array(i); // 循环去除 前start元素 while (i--) { ret[i] = list[i + start]; } return ret }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toArray</span> (<span class="hljs-params">list, start</span>) </span>{ start = start || <span class="hljs-number">0</span>; <span class="hljs-keyword">var</span> i = list.length - start; <span class="hljs-keyword">var</span> ret = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(i); <span class="hljs-comment">// 循环去除 前start元素</span> <span class="hljs-keyword">while</span> (i--) { ret[i] = list[i + start]; } <span class="hljs-keyword">return</span> ret }</code></pre> <p>上面进行了一次转换,假设<code>list</code>是[1, 2, 3, 4],<code>start</code>是1,首先创建一个包含3个元素的数组,依次执行<code>ret[2] = list[ 2 + 1]</code>、<code>ret[1] = list[ 1 + 1]</code>、<code>ret[0] = list[ 0 + 1]</code>,实际上就是去除<code>arguments</code>的第一个参数然后把剩余的类数组赋值给新的数组,其实就是去除<code>plugin</code>参数,因为调用<code>plugin.install</code>的时候不需要这个参数。</p> <p>还可以通过如下几种方式实现类数组转换成数组,但是使用<a href="http://www.js-code.com/tag/slice" title="slice" target="_blank">slice</a>会阻止某些JavaScript引擎中的优化(参考自<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments" rel="nofollow noreferrer" target="_blank">MDN</a>)。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// ES5 var args = Array.prototype.slice.call(arguments); var args = [].slice.call(arguments); // ES6 const args = Array.from(arguments); const args = [...arguments];" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="js"><span class="hljs-comment">// ES5</span> <span class="hljs-keyword">var</span> args = <span class="hljs-built_in">Array</span>.prototype.<a href="http://www.js-code.com/tag/slice" title="浏览关于“slice”的文章" target="_blank" class="tag_link">slice</a>.call(<span class="hljs-built_in">arguments</span>); <span class="hljs-keyword">var</span> args = [].slice.call(<span class="hljs-built_in">arguments</span>); <span class="hljs-comment">// ES6</span> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/const" title="浏览关于“const”的文章" target="_blank" class="tag_link">const</a></span> args = <span class="hljs-built_in">Array</span>.from(<span class="hljs-built_in">arguments</span>); <span class="hljs-keyword">const</span> args = [...arguments];</code></pre> <p>转换成数组之后调用<code>args.unshift(<a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>)</code>,把<code>Vue</code>对象添加到args的第一个参数中,这样就可以在调用<code>plugin.install</code>方法的时候把<code>Vue</code>对象传递过去。</p> <h3 id="articleHeader2">实例:实现一个插件</h3> <p>要求创建一个告诉Vue组件处理自定义<code>rules</code>规则选项的插件,这个<code>rules</code>需要一个对象,该对象指定组件中的数据的验证规则。</p> <p>示例:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const vm = new Vue({ data: { foo: 10 }, rules: { foo: { validate: value => value > 1,<br /> message: 'foo must be greater than one'<br /> }<br /> }<br /> })</p> <p>vm.foo = 0 // 输出 foo must be greater than one" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="js"><span class="hljs-keyword">const</span> vm = <span class="hljs-keyword">new</span> Vue({ <span class="hljs-attr">data</span>: { <span class="hljs-attr">foo</span>: <span class="hljs-number">10</span> }, <span class="hljs-attr">rules</span>: { <span class="hljs-attr">foo</span>: { <span class="hljs-attr">validate</span>: <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> value &gt; <span class="hljs-number">1</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'foo must be greater than one'</span> } } }) vm.foo = <span class="hljs-number">0</span> <span class="hljs-comment">// 输出 foo must be greater than one</span></code></pre> <p><strong>第一步</strong>先不考虑插件,在已有的<code>Vue</code><a href="http://www.js-code.com/tag/api" title="API" target="_blank">API</a>中是没有<code>rules</code>这个公共方法的,如果要简单实现的话可以通过钩子函数来,即在<code>created</code>里面验证逻辑。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const vm = new Vue({ data: { foo: 10 }, rules: { foo: { validate: value => value > 1,<br /> message: 'foo must be greater than one'<br /> }<br /> },<br /> created: function () {</p> <p> // 验证逻辑<br /> const rules = this.$options.rules<br /> if (rules) {<br /> Object.keys(rules).forEach(key => {</p> <p> // 取得所有规则<br /> const { validate, message } = rules[key]</p> <p> // 监听,键是变量,值是函数<br /> this.$watch(key, newValue => {</p> <p> // 验证规则<br /> const valid = validate(newValue)<br /> if (!valid) {<br /> console.log(message)<br /> }<br /> })<br /> })<br /> }<br /> }</p> <p>})<br /> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="js"><span class="hljs-keyword">const</span> vm = <span class="hljs-keyword">new</span> Vue({ <span class="hljs-attr">data</span>: { <span class="hljs-attr">foo</span>: <span class="hljs-number">10</span> }, <span class="hljs-attr">rules</span>: { <span class="hljs-attr">foo</span>: { <span class="hljs-attr">validate</span>: <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> value &gt; <span class="hljs-number">1</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'foo must be greater than one'</span> } }, <span class="hljs-attr">created</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// 验证逻辑</span> <span class="hljs-keyword">const</span> rules = <span class="hljs-keyword">this</span>.$options.rules <span class="hljs-keyword">if</span> (rules) { <span class="hljs-built_in">Object</span>.keys(rules).forEach(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> { <span class="hljs-comment">// 取得所有规则</span> <span class="hljs-keyword">const</span> { validate, message } = rules[key] <span class="hljs-comment">// 监听,键是变量,值是函数</span> <span class="hljs-keyword">this</span>.$watch(key, newValue =&gt; { <span class="hljs-comment">// 验证规则</span> <span class="hljs-keyword">const</span> valid = validate(newValue) <span class="hljs-keyword">if</span> (!valid) { <span class="hljs-built_in">console</span>.log(message) } }) }) } } }) </code></pre> <p>可以通过<code><a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.$options.rules</code>获取到自定义的<code>rules</code>对象,然后对所有规则遍历,使用自定义的<code>validate(newValue)</code>验证规则。</p> <p><strong>第二步</strong>实现这个<code>rules</code>插件,为了在<code>Vue</code>中直接使用,可以通过<code>Vue.mixin</code>注入到<code>Vue</code>组件中,这样所有的<code>Vue</code>实例都可以使用。</p> <div class="google-auto-placed ap_container" style="text-align: center; width: 100%; height: auto; clear: none;"><ins data-ad-format="auto" class="adsbygoogle adsbygoogle-noablate" data-ad-client="ca-pub-6330872677300335" data-adsbygoogle-status="done" style="display: block; margin: auto; background-color: transparent;"><ins id="aswift_4_expand" style="display: inline-table; border: none; height: 0px; margin: 0px; padding: 0px; position: relative; visibility: visible; width: 697px; background-color: transparent;"><ins id="aswift_4_anchor" style="display: block; border: none; height: 0px; margin: 0px; padding: 0px; position: relative; visibility: visible; width: 697px; background-color: transparent; overflow: hidden; opacity: 0;"><iframe width="697" height="175" frameborder="0" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no" allowfullscreen="true" onload="var i=this.id,s=window.google_iframe_oncopy,H=s&amp;&amp;s.handlers,h=H&amp;&amp;H[i],w=this.contentWindow,d;try{d=w.document}catch(e){}if(h&amp;&amp;d&amp;&amp;(!d.body||!d.body.firstChild)){if(h.call){setTimeout(h,0)}else if(h.match){try{h=s.upd(h,i)}catch(e){}w.location.replace(h)}}" id="aswift_4" name="aswift_4" style="left:0;position:absolute;top:0;border:0px;width:697px;height:175px;"></iframe></ins></ins></ins></div> <p>按照插件的开发流程,应该有一个公开方法<code>install</code>,在<code>install</code>里面使用全局的<code>mixin</code>方法添加一些组件选项,<code>mixin</code>方法包含一个<code>created</code>钩子函数,在钩子函数中验证<code>this.$options.rules</code>。</p> <p>实现代码如下:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="import Vue from 'vue' // 定义插件 const RulesPlugin = { // 插件应该有一个公开方法install // 第一个参数是Vue 构造器 // 第二个参数是一个可选的选项对象 install (Vue) { // 注入组件 Vue.mixin({ // 钩子函数 created: function () { // 验证逻辑 const rules = this.$options.rules if (rules) { Object.keys(rules).forEach(key => {</p> <p> // 取得所有规则<br /> const { validate, message } = rules[key]</p> <p> // 监听,键是变量,值是函数<br /> this.$watch(key, newValue => {</p> <p> // 验证规则<br /> const valid = validate(newValue)<br /> if (!valid) {<br /> console.log(message)<br /> }<br /> })<br /> })<br /> }<br /> }<br /> })<br /> }<br /> }</p> <p>// 调用插件,实际上就是调用插件的install方法<br /> // 即RulesPlugin.install(Vue)<br /> Vue.use(RulesPlugin)" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="js"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span> <span class="hljs-comment">// 定义插件</span> <span class="hljs-keyword">const</span> RulesPlugin = { <span class="hljs-comment">// 插件应该有一个公开方法install</span> <span class="hljs-comment">// 第一个参数是Vue 构造器</span> <span class="hljs-comment">// 第二个参数是一个可选的选项对象</span> install (Vue) { <span class="hljs-comment">// 注入组件</span> Vue.mixin({ <span class="hljs-comment">// 钩子函数</span> created: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// 验证逻辑</span> <span class="hljs-keyword">const</span> rules = <span class="hljs-keyword">this</span>.$options.rules <span class="hljs-keyword">if</span> (rules) { <span class="hljs-built_in">Object</span>.keys(rules).forEach(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> { <span class="hljs-comment">// 取得所有规则</span> <span class="hljs-keyword">const</span> { validate, message } = rules[key] <span class="hljs-comment">// 监听,键是变量,值是函数</span> <span class="hljs-keyword">this</span>.$watch(key, newValue =&gt; { <span class="hljs-comment">// 验证规则</span> <span class="hljs-keyword">const</span> valid = validate(newValue) <span class="hljs-keyword">if</span> (!valid) { <span class="hljs-built_in">console</span>.log(message) } }) }) } } }) } } <span class="hljs-comment">// 调用插件,实际上就是调用插件的install方法</span> <span class="hljs-comment">// 即RulesPlugin.install(Vue)</span> Vue.use(RulesPlugin)</code></pre> <h3 id="articleHeader3">参考</h3> <blockquote><p> <a href="https://cn.vuejs.org/v2/guide/plugins.html" rel="nofollow noreferrer" target="_blank">Vue官网之插件Plugins</a> <br /><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments" rel="nofollow noreferrer" target="_blank">MDN之Arguments 对象</a> </p></blockquote> <h4>交流</h4> <p>本人Github链接如下,欢迎各位Star</p> <p><a href="http://github.com/yygmind/blog" rel="nofollow noreferrer" target="_blank">http://github.com/yygmind/blog</a></p> <p>我是木易杨,网易高级前端工程师,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!</p> <p>如果你想加群讨论每期面试知识点,公众号回复[加群]即可<br /><span class="img-wrap"><img data-src="/img/remote/1460000016890954?w=1325&amp;h=897" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="" title="" style="cursor: pointer;"></span></p> <p></code></p>

总结

以上是脚本宝典为你收集整理的

Vue 进阶系列(二)之插件原理及实现

全部内容,希望文章能够帮你解决

Vue 进阶系列(二)之插件原理及实现

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过