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

【Vue】组件的基础与组件间通信

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。
<p><code></p> <blockquote><p><a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>.js 最核心的功能就是组件(Component),从组件的构建、注册到组件间通信,<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a> 2.x 提供了更多方式,让我们更灵活地使用组件来实现不同需求。</p></blockquote> <h1 id="articleHeader0">一、构建组件</h1> <h2 id="articleHeader1">1.1 组件基础</h2> <p>一个组件由 template、data、computed、methods等选项组成。需要注意:</p> <ul> <li>template 的 <a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a> 结构必须有根元素</li> <li>data 必须是函数,数据通过 <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> 返回出去</li> </ul> <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="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="// 示例:定义一个组件 MyComponent<br /> <a href="http://www.js-code.com/tag/var" title="var" target="_blank">var</a> MyComponent = {{<br /> data: <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a> () {<br /> <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> {<br /> // 数据<br /> }<br /> },<br /> template: '</p> <div>组件内容</div> <p>'<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs actionscript"><code><span class="hljs-comment">// 示例:定义一个组件 MyComponent</span> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/var" title="浏览关于“var”的文章" target="_blank" class="tag_link">var</a></span> MyComponent = {{ data: <span class="hljs-function"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/function" title="浏览关于“function”的文章" target="_blank" class="tag_link">function</a></span> <span class="hljs-params">()</span> </span>{ <span class="hljs-keyword"><a href="http://www.js-code.com/tag/return" title="浏览关于“return”的文章" target="_blank" class="tag_link">return</a></span> { <span class="hljs-comment">// 数据</span> } }, template: <span class="hljs-string">'&lt;<a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a>&gt;组件内容&lt;/div&gt;'</span> }</code></pre> <p>由于 <a href="http://www.js-code.com/tag/html" title="HTML" target="_blank">HTML</a> 特性不区分大小写, 在使用<code>kebab-<a href="http://www.js-code.com/tag/case" title="case" target="_blank">case</a></code>(小写短横线分隔命名) 定义组件时,引用也需要使用这个格式如 <code>&lt;my-component&gt;</code>来使用;在使用<code>PascalCase</code>(驼峰式命名) 定义组件时<code>&lt;my-component&gt;</code>和<code>&lt;MyComponent&gt;</code>这两种格式都可以引用。</p> <h2 id="articleHeader2">1.2 单文件组件.vue</h2> <p>如果项目中使用打包编译工具 webpack,那引入 vue-loader 就可以使用 <code>.vue</code>后缀文件构建组件。<br />一个<code>.vue</code>单文件组件 (SFC) 示例:</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="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="// MyComponent.vue 文件<br /> <template></p> <div>组件内容</div> <p></template></p> <p><script> <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> <a href="http://www.js-code.com/tag/default" title="default" target="_blank">default</a> { data () { <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> { // 数据 } } } </script></p> <style scoped> <a href="http://www.js-code.com/tag/div" title="div" target="_blank">div</a>{ color: red } </style> <p>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code>// MyComponent.vue 文件 <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>组件内容<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/export" title="浏览关于“export”的文章" target="_blank" class="tag_link">export</a></span> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/default" title="浏览关于“default”的文章" target="_blank" class="tag_link">default</a></span> { data () { <span class="hljs-keyword">return</span> { <span class="hljs-comment">// 数据</span> } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css"> <span class="hljs-selector-tag">div</span>{ <span class="hljs-attribute">color</span>: red } </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></code></pre> <p><code>.vue</code>文件使组件结构变得清晰,使用<code>.vue</code>还需要安装 vue-style-loader 等加载器并配置 webpack.config.js 来支持对 .vue 文件及 ES6 语法的解析。</p> <blockquote><p>进一步学习可参考文章:<a href="https://segmentfault.com/a/1190000015708749">详解 SFC 与 vue-loader</a> </p></blockquote> <h1 id="articleHeader3">二、注册组件</h1> <h2 id="articleHeader4">2.1 手动注册</h2> <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="// 全局注册,任何 Vue 实例都可引用 Vue.component('my-component', MyComponent) // 局部注册,在注册实例的作用域下有效 var MyComponent = { /* ... */ } new Vue({ components: { 'my-component': MyComponent } }) // 局部注册,使用模块系统,组件定义在统一文件夹中 import MyComponent from './MyComponent.vue' export default { components: { MyComponent // ES6 语法,相当于 MyComponent: MyComponent } }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code><span class="hljs-comment">// 全局注册,任何 <a href="http://www.js-code.com/tag/vue" title="浏览关于“Vue”的文章" target="_blank" class="tag_link">Vue</a> 实例都可引用</span> Vue.component(<span class="hljs-string">'my-component'</span>, MyComponent) <span class="hljs-comment">// 局部注册,在注册实例的作用域下有效</span> <span class="hljs-keyword">var</span> MyComponent = { <span class="hljs-comment">/* ... */</span> } <span class="hljs-keyword"><a href="http://www.js-code.com/tag/new" title="浏览关于“new”的文章" target="_blank" class="tag_link">new</a></span> Vue({ components: { <span class="hljs-string">'my-component'</span>: MyComponent } }) <span class="hljs-comment">// 局部注册,使用模块系统,组件定义在统一文件夹中</span> <span class="hljs-keyword">import</span> MyComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./MyComponent.vue'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { components: { MyComponent <span class="hljs-comment">// ES6 语法,相当于 MyComponent: MyComponent</span> } }</code></pre> <p>注意全局注册的行为必须在根 Vue 实例 (通过 <a href="http://www.js-code.com/tag/new" title="new" target="_blank">new</a> Vue) 创建之前发生。</p> <h2 id="articleHeader5">2.2 自动注册</h2> <p>对于通用模块使用枚举的注册方式代码会非常不方便,推荐使用自动化的全局注册。如果项目使用 webpack,就可以使用其中的<code>require.con<a href="http://www.js-code.com/tag/text" title="浏览关于“text”的文章" target="_blank" class="tag_link">text</a></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="import Vue from 'vue' import upperFirst from 'lodash/upperFirst' // 使用 lodash 进行字符串处理 import camelCase from 'lodash/camelCase' const requireComponent = require.context( './components', // 其组件目录的相对路径 false, // 是否查询其子目录 /Base[A-Z]w+.(vue|js)$/ // 匹配基础组件文件名的正则表达式 ) requireComponent.keys().forEach(fileName => {<br /> // 获取组件配置<br /> const componentConfig = requireComponent(fileName)</p> <p> // 获取组件的 PascalCase 命名<br /> const componentName = upperFirst(<br /> camelCase(<br /> // 剥去文件名开头的 `./` 和结尾的扩展名<br /> fileName.replace(/^./(.*).w+$/, '$1')<br /> )<br /> )</p> <p> // 全局注册组件<br /> Vue.component(<br /> componentName,<br /> componentConfig.default || componentConfig<br /> )<br /> })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span> <span class="hljs-keyword">import</span> upperFirst <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash/upperFirst'</span> <span class="hljs-comment">// 使用 lodash 进行字符串处理</span> <span class="hljs-keyword">import</span> camelCase <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash/camelCase'</span> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/const" title="浏览关于“const”的文章" target="_blank" class="tag_link">const</a></span> requireComponent = <span class="hljs-built_in">require</span>.context( <span class="hljs-string">'./components'</span>, <span class="hljs-comment">// 其组件目录的相对路径</span> <span class="hljs-literal"><a href="http://www.js-code.com/tag/false" title="浏览关于“false”的文章" target="_blank" class="tag_link">false</a></span>, <span class="hljs-comment">// 是否查询其子目录</span> /Base[A-Z]w+.(vue|js)$/ <span class="hljs-comment">// 匹配基础组件文件名的正则表达式</span> ) requireComponent.keys().<a href="http://www.js-code.com/tag/for" title="浏览关于“for”的文章" target="_blank" class="tag_link">for</a>Each(<span class="hljs-function"><span class="hljs-params">fileName</span> =&gt;</span> { <span class="hljs-comment">// 获取组件配置</span> <span class="hljs-keyword">const</span> componentConfig = requireComponent(fileName) <span class="hljs-comment">// 获取组件的 PascalCase 命名</span> <span class="hljs-keyword">const</span> componentName = upperFirst( camelCase( <span class="hljs-comment">// 剥去文件名开头的 `./` 和结尾的扩展名</span> fileName.replace(<span class="hljs-regexp">/^./(.*).w+$/</span>, <span class="hljs-string">'$1'</span>) ) ) <span class="hljs-comment">// 全局注册组件</span> Vue.component( componentName, componentConfig.default || componentConfig ) })</code></pre> <h1 id="articleHeader6">三、组件通信</h1> <h2 id="articleHeader7">3.1 父单向子的 props</h2> <p>Vue 2.x 以后父组件用<code>props</code>向子组件传递数据,这种传递是单向/正向的,反之不能。这种设计是为了避免子组件无意间修改父组件的状态。</p> <p>子组件需要选项<code>props</code>声明从父组件接收的数据,<code>props</code>可以是<strong>字符串<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a></strong>和<strong>对象</strong>,一个 .vue 单文件组件示例如下</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="<a href="http://www.js-code.com/tag/button" title="浏览关于“button”的文章" target="_blank" class="tag_link">button</a>" class="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="浏览关于“top”的文章" target="_blank" class="tag_link">top</a>" data-clipboard-text="// ChildComponent.vue<br /> <template></p> <div> <b>子组件:</b>{{message}} </div> <p></template></p> <p><script> <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> <a href="http://www.js-code.com/tag/default" title="default" target="_blank">default</a> { <a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>: &quot;ChildComponent&quot;, props: ['message'] } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// ChildComponent.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>子组件:<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>{{message}} <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr"><a href="http://www.js-code.com/tag/name" title="浏览关于“name”的文章" target="_blank" class="tag_link">name</a></span>: <span class="hljs-string">"ChildComponent"</span>, <span class="hljs-attr">props</span>: [<span class="hljs-string">'message'</span>] } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>父组件可直接传单个数据值,也可以可以使用指令<code>v-b<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>d</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="// <a href="http://www.js-code.com/tag/parent" title="parent" target="_blank">parent</a>Component.vue<br /> <template></p> <div> <h1>父组件</h1> <p> <ChildComponent message=&quot;父组件向子组件传递的非动态值&quot;></ChildComponent><br /> <input type=&quot;text&quot; v-model=&quot;parentMassage&quot;/><br /> <ChildComponent :message=&quot;parentMassage&quot;></ChildComponent> </div> <p></template></p> <p><script> <a href="http://www.js-code.com/tag/import" title="import" target="_blank">import</a> ChildComponent from '@/components/ChildComponent' <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> default { components: { ChildComponent }, data () { <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> { <a href="http://www.js-code.com/tag/parent" title="parent" target="_blank">parent</a>Massage: '' } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// <a href="http://www.js-code.com/tag/parent" title="浏览关于“parent”的文章" target="_blank" class="tag_link">parent</a>Component.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>父组件<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">message</span>=<span class="hljs-string">"父组件向子组件传递的非动态值"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ChildComponent</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name"><a href="http://www.js-code.com/tag/in" title="浏览关于“in”的文章" target="_blank" class="tag_link">in</a>put</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"parentMassage"</span>/&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:message</span>=<span class="hljs-string">"parentMassage"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ChildComponent</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">import</span> ChildComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ChildComponent'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">components</span>: { ChildComponent }, data () { <span class="hljs-keyword">return</span> { <span class="hljs-attr">parentMassage</span>: <span class="hljs-string">''</span> } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>配置路由后运行效果如下:<br /><span class="img-wrap"><img data-src="/img/bVbgZqB?w=1728&amp;h=410" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <h2 id="articleHeader8">3.2 子向父的 $emit</h2> <p>当子组件向父组件传递数据时,就要用到<strong>自定义事件</strong>。子组件中使用 <code>$emit()</code>触发自定义事件,父组件使用<code>$on()</code>监听,类似观察者模式。</p> <p>子组件<code>$emit()</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="// ChildComponent.vue <template></p> <div> <b>子组件:</b><button @click=&quot;handleIncrease&quot;>传递数值给父组件</button> </div> <p></template></p> <p><script> <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> default { <a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>: &quot;ChildComponent&quot;, methods: { handleIncrease () { <a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.$emit('<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>crease',5) } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// ChildComponent.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>子组件:<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"handleIncrease"</span>&gt;</span>传递数值给父组件<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">name</span>: <span class="hljs-string">"ChildComponent"</span>, <span class="hljs-attr">methods</span>: { handleIncrease () { <span class="hljs-keyword"><a href="http://www.js-code.com/tag/this" title="浏览关于“this”的文章" target="_blank" class="tag_link">this</a></span>.$emit(<span class="hljs-string">'increase'</span>,<span class="hljs-number">5</span>) } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>父组件监听自定义事件 increase,并做出响应的示例:</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="// parentComponent.vue <template></p> <div> <h1>父组件</h1> <p>数值:{{total}}</p> <p> <ChildComponent @increase=&quot;getTotal&quot;></ChildComponent> </div> <p></template></p> <p><script> <a href="http://www.js-code.com/tag/import" title="import" target="_blank">import</a> ChildComponent from '@/components/ChildComponent' export default { components: { ChildComponent }, data () { return { total: 0 } }, methods: { getTotal (count) { <a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.total = count } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// parentComponent.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>父组件<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>数值:{{total}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> @<span class="hljs-attr">increase</span>=<span class="hljs-string">"getTotal"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ChildComponent</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">import</span> ChildComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ChildComponent'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">components</span>: { ChildComponent }, data () { <span class="hljs-keyword">return</span> { <span class="hljs-attr">total</span>: <span class="hljs-number">0</span> } }, <span class="hljs-attr">methods</span>: { getTotal (count) { <span class="hljs-keyword">this</span>.total = count } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>访问 parentComponent.vue 页面,点击按钮后子组件将数值传递给父组件:<br /><span class="img-wrap"><img data-src="/img/bVbgZDF?w=1884&amp;h=556" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <h2 id="articleHeader9">3.3 子孙的链与索引</h2> <p>组件的关系有很多时跨级的,这些组件的调用形成多个父链与子链。父组件可以通过<code><a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.$children</code>访问它所有的子组件,可无限递归向下访问至最内层的组件,同理子组件可以通过<code><a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.$parent</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="// parentComponent.vue <template></p> <div> <p>{{message}}</p> <p> <ChildComponent></ChildComponent> </div> <p></template></p> <p>// ChildComponent.vue<br /> <template></p> <div> <b>子组件:</b><button @click=&quot;handleChange&quot;>通过父链直接修改数据</button> </div> <p></template></p> <p><script> export default { name: &quot;ChildComponent&quot;, methods: { handleChange () { <a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.$parent.message = '来自 ChildComponent 的内容' } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// parentComponent.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{message}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ChildComponent</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> // ChildComponent.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>子组件:<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"handleChange"</span>&gt;</span>通过父链直接修改数据<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">name</span>: <span class="hljs-string">"ChildComponent"</span>, <span class="hljs-attr">methods</span>: { handleChange () { <span class="hljs-keyword">this</span>.$parent.message = <span class="hljs-string">'来自 ChildComponent 的内容'</span> } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>显然点击父组件页面的按钮后会收到子组件传过来的 message。</p> <blockquote><p>在业务中应尽量避免使用父链或子链,因为这种数据依赖会使父子组件紧耦合,一个组件可能被其他组件任意修改显然是不好的,所以组件父子通信常用<code>props</code>和<code>$emit</code>。</p></blockquote> <h2 id="articleHeader10">3.4 中央事件总线 Bus</h2> <p>子孙的链式通信显然会使得组件紧耦合,同时兄弟组件间的通信该如何实现呢?这里介绍中央事件总线的方式,实际上就是<strong>用一个vue实例(Bus)作为媒介</strong>,需要通信的组件都引入 Bus,之后通过分别触发和监听 Bus 事件,进而实现组件之间的通信和参数传递。</p> <p>首先建 Vue 实例作为总线:</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="// Bus.js import Vue from 'vue' export default new Vue;" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code><span class="hljs-comment">// Bus.js</span> <span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">new</span> Vue;</code></pre> <p>需要通信的组件都引入 Bus.js,使用 <code>$emit</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="// ComponentA.vue <template></p> <div> <b>组件A:</b><button @click=&quot;handleBus&quot;>传递数值给需要的组件</button> </div> <p></template></p> <p><script> import Bus from './bus.js' export default { methods: { handleBus () { Bus.$emit('someBusMessage','来自ComponentA的数据') } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// ComponentA.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>组件A:<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"handleBus"</span>&gt;</span>传递数值给需要的组件<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">import</span> Bus <span class="hljs-keyword">from</span> <span class="hljs-string">'./bus.js'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">methods</span>: { handleBus () { Bus.$emit(<span class="hljs-string">'someBusMessage'</span>,<span class="hljs-string">'来自ComponentA的数据'</span>) } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>需要组件A信息的就使用<code>$on</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="// ComponentB.vue <template></p> <div> <b>组件B:</b><button @click=&quot;handleBus&quot;>接收组件A的信息</button></p> <p>{{message}}</p> </p></div> <p></template></p> <p><script> import Bus from './bus.js' export default { data() { return { message: '' } }, created () { <a href="http://www.js-code.com/tag/let" title="let" target="_blank">let</a> that = <a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a> // 保存当前对象的作用域this Bus.$on('someBusMessage',<a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a> (data) { that.message = data }) }, be<a href="http://www.js-code.com/tag/for" title="for" target="_blank">for</a>eDestroy () { // 手动销毁 $on 事件,防止多次触发 Bus.$off('someBusMessage', this.someBusMessage) } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code>// ComponentB.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>组件B:<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"handleBus"</span>&gt;</span>接收组件A的信息<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{message}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">import</span> Bus <span class="hljs-keyword">from</span> <span class="hljs-string">'./bus.js'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { data() { <span class="hljs-keyword">return</span> { <span class="hljs-attr">message</span>: <span class="hljs-string">''</span> } }, created () { <span class="hljs-keyword"><a href="http://www.js-code.com/tag/let" title="浏览关于“let”的文章" target="_blank" class="tag_link">let</a></span> that = <span class="hljs-keyword">this</span> <span class="hljs-comment">// 保存当前对象的作用域this</span> Bus.$on(<span class="hljs-string">'someBusMessage'</span>,<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{ that.message = data }) }, beforeDestroy () { <span class="hljs-comment">// 手动销毁 $on 事件,防止多次触发</span> Bus.$off(<span class="hljs-string">'someBusMessage'</span>, <span class="hljs-keyword">this</span>.someBusMessage) } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <h1 id="articleHeader11">四、递归组件</h1> <p>组件可以在自己的 template 模板中调用自己,需要设置 name 选择。</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="// 递归组件 ComponentRecursion.vue <template></p> <div> <p>递归组件</p> <p> <ComponentRecursion :count=&quot;count + 1&quot; v-<a href="http://www.js-code.com/tag/if" title="if" target="_blank">if</a>=&quot;count < 3&quot;></ComponentRecursion> </div> <p></template></p> <p><script> export default { name: &quot;ComponentRecursion&quot;, props: { count: { type: <a href="http://www.js-code.com/tag/Number" title="Number" target="_blank">Number</a>, default: 1 } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// 递归组件 ComponentRecursion.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>递归组件<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">ComponentRecursion</span> <span class="hljs-attr">:count</span>=<span class="hljs-string">"count + 1"</span> <span class="hljs-attr">v-<a href="http://www.js-code.com/tag/if" title="浏览关于“if”的文章" target="_blank" class="tag_link">if</a></span>=<span class="hljs-string">"count &lt; 3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ComponentRecursion</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">name</span>: <span class="hljs-string">"ComponentRecursion"</span>, <span class="hljs-attr">props</span>: { <span class="hljs-attr">count</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in"><a href="http://www.js-code.com/tag/Number" title="浏览关于“Number”的文章" target="_blank" class="tag_link">Number</a></span>, <span class="hljs-attr">default</span>: <span class="hljs-number">1</span> } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>如果递归组件没有 count 等限制数量,就会抛出错误(Uncaught RangeError: Maximum c<a href="http://www.js-code.com/tag/all" title="all" target="_blank">all</a> stack size exceeded)。</p> <p>父页面使用该递归组件,在 Chrome 中的 <strong>Vue Devtools</strong> 可以看到组件递归了三次:<br /><span class="img-wrap"><img data-src="/img/bVbg0TJ?w=2122&amp;h=608" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <blockquote><p>递归组件可以开发未知层级关系的独立组件,如级联选择器和树形控件等。</p></blockquote> <h1 id="articleHeader12">五、动态组件</h1> <p>如果将一个 Vue 组件命名为 Component 会报错(Do not use built-in or reserved <a href="http://www.js-code.com/tag/html" title="HTML" target="_blank">HTML</a> <a href="http://www.js-code.com/tag/element" title="element" target="_blank">element</a>s as component id: Component),因为 Vue 提供了特殊的元素 <code>&lt;component&gt;</code>来动态挂载不同的组件,并使用 <code>is</code> 特性来选择要挂载的组件。</p> <p>以下是使用<code>&lt;component&gt;</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="// parentComponent.vue <template></p> <div> <h1>父组件</h1> <p> <component :is=&quot;currentView&quot;></component><br /> <button @click = &quot;changeToViewB&quot;>切换到B视图</button> </div> <p></template></p> <p><script> import ComponentA from '@/components/ComponentA' import ComponentB from '@/components/ComponentB' export default { components: { ComponentA, ComponentB }, data() { return { currentView: ComponentA // 默认显示组件 A } }, methods: { changeToViewB () { this.currentView = ComponentB // 切换到组件 B } } } </script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code class="vue">// parentComponent.vue <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>父组件<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">:is</span>=<span class="hljs-string">"currentView"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span> = <span class="hljs-string">"changeToViewB"</span>&gt;</span>切换到B视图<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">import</span> ComponentA <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ComponentA'</span> <span class="hljs-keyword">import</span> ComponentB <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ComponentB'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-attr">components</span>: { ComponentA, ComponentB }, data() { <span class="hljs-keyword">return</span> { <span class="hljs-attr">currentView</span>: ComponentA <span class="hljs-comment">// 默认显示组件 A</span> } }, <span class="hljs-attr">methods</span>: { changeToViewB () { <span class="hljs-keyword">this</span>.currentView = ComponentB <span class="hljs-comment">// 切换到组件 B</span> } } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>改变 <code>this.currentView</code>的值就可以自由切换 AB 组件:<br /><span class="img-wrap"><img data-src="/img/bVbg0WS?w=1344&amp;h=336" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <blockquote><p>与之类似的是<code>vue-router</code>的实现原理,前端路由到不同的页面实际上就是加载不同的组件。</p></blockquote> <hr> <h4>要继续加油呢,少年!</h4> <p></code></p>

总结

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

【Vue】组件的基础与组件间通信

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

【Vue】组件的基础与组件间通信

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

80%的人都看过