组件
- 组件(Component )是Vue.js最强大的功能之一
- 特性 一个页面由不同的组件构成
- 组件 可以扩展HTML元素,封装可重用的代码
组件注册
全局注册
-
格式:Vue.component(“组件名称”,{} )第一个参数是标签名称,第二个参数是选项对象
-
为什么要用短横线的方式使用组件,因为在html中对大小写不敏感(也就是不区分大小写)
-
全局组件注册后,任何的Vue实例(组件 )都可以用
<div id="app"> <!-- 4、组件可以重复使用多次 data是一个函数由于作用域的关系,每个组件的数据互不干扰 --> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> <!-- 8、必须使用短横线的方式使用组件 --> <!-- 组件的名称相当于HTML标签 --> <hello-world></hello-world> </div> <script type="text/javascript"> // 7、如果使用驼峰式命名组件,必须使用短横线的方式使用组件 Vue.component('HelloWorld', { data: function(){ return { msg: 'HelloWorld' } }, template: '<div>{{msg}}</div>' }); Vue.component('button-counter', { // 1、组件参数的data值必须是函数 // 同时这个函数要求返回一个对象 data: function(){ return { count: 0 } }, // 2、组件模板必须是单个根元素 <div><div> // 3、组件模板的内容可以是模板字符串 template: ` <div> <button @click="handle">点击了{{count}}次</button> <button>测试123</button> # 6 在字符串模板中可以使用驼峰的方式使用组件 <HelloWorld></HelloWorld> </div> `, //在组件中也可以定义methods methods: { handle: function(){ this.count += 2; } } }) // 创建根实例 var vm = new Vue({ el: '#app', data: { sum:1 } }); </script>
-
全局注册的注意事项
- data必须为函数返回一个对象的结构 (data是函数时,在重复使用同一个组件时,由于每个组件都有自己的作用域,每个组件相互独立,互不响应)
- 为什么data不能为对象,因为data如果是对象也就是引用数据类型 ,在重复使用同一个组件时,每一个组件的data都是同一个地址,使用data数据会相互影响,也就是浅拷贝。
局部注册
-
局部组件只能在注册它的父组件(Vue实例)中使用 (如
<div id="app"> </div>
中使用 ) -
如果在全局组件的模板字符串中使用,则会报错
<div id="app"> <my-component></my-component> </div> <script> // 定义组件的模板 var Child = { template: '<div>A custom component!</div>' } new Vue({ el:"#app" //局部注册组件 components: { // <my-component> 将只在父模板可用 一定要在实例上注册了才能在html文件中使用 'my-component': Child } }) </script>
Vue组件之间传值
父组件向子组件传值
-
在父组件中使用子组件传值:在子组件身上定义属性并绑定要传递的值
-
在子组件中使用props接收
-
props是单身数据流,只能用在父传子
-
:title加
:
与不加:
的区别 ,如果不加引号title
传递的值是字符串如果加引号
title
是一个动态的变量用来传递数据<div id="app"> <div>{{pmsg}}</div> <!--1、menu-item 在 APP中嵌套着 故 menu-item 为 子组件 --> <!-- 给子组件传入一个静态的值 --> <menu-item title='来自父组件的值'></menu-item> <!-- ptitle是父组件中data的数据 传的值可以是数字、对象、数组等等 --> <menu-item :title='ptitle' content='hello'></menu-item> </div> <script type="text/javascript"> Vue.component('menu-item', { // 3、 子组件用属性props接收父组件传递过来的数据 props: ['title', 'content'], data: function() { return { msg: '子组件本身的数据' } }, //在模板中使用父组件传递过来的值 template: '<div>{{msg + "----" + title + "-----" + content}}</div>' }); var vm = new Vue({ el: '#app', data: { pmsg: '父组件中内容', ptitle: '动态绑定属性' } }); </script>
子组件向父组件传值
-
子组件用
$emit()
触发事件,触发绑定在父组件的自定义事件(也就是$emit()
的第一个参数) -
$emit()
的第一个参数为自定义事件名称,第二个参数为需要传递的数据 -
父组件等待子组件触发事件
-
子组件通过调用父组件的方法来完成数据的传递,本质就是调用函数传参
<div id="app"> <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div> <!-- 2 父组件用v-on 监听子组件的事件 这里 enlarge-text 是从 $emit 中的第一个参数对应 通过$event获取第二个参数, handle 为对应的事件处理函数 --> <menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> /* 子组件向父组件传值-携带参数 */ Vue.component('menu-item', { props: ['parr'], template: ` <div> <ul> <li :key='index' v-for='(item,index) in parr'>{{item}}</li> </ul> ### 1、子组件用$emit()触发事件 ### 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据 <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button> <button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button> </div> ` }); var vm = new Vue({ el: '#app', data: { pmsg: '父组件中内容', parr: ['apple','orange','banana'], fontSize: 10 }, methods: { handle: function(val){ // 扩大字体大小 this.fontSize += val; } } }); </script>
兄弟之间的传递
-
兄弟之间传递数据需要借助事件中心,通过事件中心传递数据
- 提供事件中心 var hub=new Vue()
-
传递数据方,通过hub.$emit(方法名,传递的数据 )事件触发兄弟的钩子函数
-
接收数据方,通过mounted(){hub.$on(“方法名”, (接收传递过来的数据)=>{} }
-
销毁事件, 通过hub.$off() 方法名销毁事件之后无法进行传递数据
<div id="app"> <div>父组件</div> <div> <button @click='handle'>销毁事件</button> </div> <test-tom></test-tom> <test-jerry></test-jerry> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> /* 兄弟组件之间数据传递 */ //1、 提供事件中心 var hub = new Vue(); Vue.component('test-tom', { data: function(){ return { num: 0 } }, template: ` <div> <div>TOM:{{num}}</div> <div> <button @click='handle'>点击</button> </div> </div> `, methods: { handle: function(){ //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件 hub.$emit('jerry-event', 2); } }, mounted: function() { // 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on(方法名 hub.$on('tom-event', (val) => { this.num += val; }); } }); Vue.component('test-jerry', { data: function(){ return { num: 0 } }, template: ` <div> <div>JERRY:{{num}}</div> <div> <button @click='handle'>点击</button> </div> </div> `, methods: { handle: function(){ //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件 hub.$emit('tom-event', 1); } }, mounted: function() { // 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名 hub.$on('jerry-event', (val) => { this.num += val; }); } }); var vm = new Vue({ el: '#app', data: { }, methods: { handle: function(){ //4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据 hub.$off('tom-event'); hub.$off('jerry-event'); } } }); </script>
组件插槽
-
组件的最大特性就是利用性,而用好插槽能大大提高组件的复用性
-
父组件向子组件传递内容
匿名插槽
<div id="app">
<!-- 这里的所有组件标签中嵌套的内容会替换掉slot 如果不传值 则使用 slot 中的默认值 -->
<alert-box>有bug发生</alert-box>
<alert-box>有一个警告</alert-box>
<alert-box></alert-box>
</div>
<script type="text/javascript">
/*
组件插槽:父组件向子组件传递内容
*/
Vue.component('alert-box', {
template: `
<div>
<strong>ERROR:</strong>
# 当组件渲染的时候,这个 <slot> 元素将会被替换为“组件标签中嵌套的内容”。
# 插槽内可以包含任何模板代码,包括 HTML
<slot>默认内容</slot>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
}
});
</script>
</body>
</html>
具名插槽
-
如slot标签上有属性name,则它是叫具名插槽,否则叫匿名插槽
-
根据标签中的属性
slot='header'
,对应组件中的模板<slot name='header'></slot>
进行匹配 -
使用
<template slot='header'> </template>
标签包裹可以传递多条内容并且template不会渲染到页面上<div id="app"> <base-layout> <!-- 2、 通过slot属性来指定, 这个slot的值必须和下面slot组件得name值对应上 如果没有匹配到 则放到匿名的插槽中 --> <p slot='header'>标题信息</p> <p>主要内容1</p> <p>主要内容2</p> <p slot='footer'>底部信息信息</p> </base-layout> <base-layout> <!-- 注意点:template临时的包裹标签最终不会渲染到页面上 --> <template slot='header'> <p>标题信息1</p> <p>标题信息2</p> </template> <p>主要内容1</p> <p>主要内容2</p> <template slot='footer'> <p>底部信息信息1</p> <p>底部信息信息2</p> </template> </base-layout> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> /* 具名插槽 */ Vue.component('base-layout', { template: ` <div> <header> ### 1、 使用 <slot> 中的 "name" 属性绑定元素 指定当前插槽的名字 <slot name='header'></slot> </header> <main> <slot></slot> </main> <footer> ### 注意点: ### 具名插槽的渲染顺序,完全取决于模板,而不是取决于父组件中元素的顺序 <slot name='footer'></slot> </footer> </div> ` }); var vm = new Vue({ el: '#app', data: { } }); </script> </body> </html>
作用域插槽
-
父组件对子组件的内容加工
-
在父组件中使用
slot-scope
属性,接收子组件绑定的属性上的数据 ,然后进行加工。<div id="app"> <!-- 1、当我们希望li 的样式由外部使用组件的地方定义,因为可能有多种地方要使用该组件, 但样式希望不一样 这个时候我们需要使用作用域插 --> <fruit-list :list='list'> <!-- 2、 父组件中使用了<template>元素,而且包含slot-scope="slotProps", slotProps在这里只是临时变量 ---> <!-- 用slot-scope接收子组件item属性上的数据,然后用v-if加工数据--> <template slot-scope='slotProps'> <strong v-if='slotProps.info.id==3' class="current"> {{slotProps.info.name}} </strong> <span v-else>{{slotProps.info.name}}</span> </template> </fruit-list> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> /* 作用域插槽 */ Vue.component('fruit-list', { //用props来接收父组件中的数据 props: ['list'], template: ` <div> <li :key='item.id' v-for='item in list'> ### 3、 在子组件模板中,<slot>元素上有一个类似props传递数据给组件的写法msg="xxx", ### 插槽可以提供一个默认内容,如果父组件没有为这个插槽提供了内容,会显示默认的内容。 如果父组件为这个插槽提供了内容,则默认的内容会被替换掉 <slot :info='item'>{{item.name}}</slot> </li> </div> ` }); var vm = new Vue({ el: '#app', data: { list: [{ id: 1, name: 'apple' },{ id: 2, name: 'orange' },{ id: 3, name: 'banana' }] } }); </script> </body> </html>
Vue-路由
「点赞、收藏和评论」
❤️关注+点赞+收藏+评论+转发❤️,鼓励笔者创作更好的文章,谢谢?大家。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!