目录
一、初识组件
1.1 什么是组件?什么是组件化?
1.2 Vue中如何创建组件?
1.3 组件内的 scoped 是如何工作的?
1.4 组件切换
1.5 动态组件--component
1.6 组件缓存--keep-alive
1.7 异步组件
二、组件动画
2.1 如何给组件添加动画 ?
2.2 组件动画示例
三、父子组件
3.1 什么是父子组件?
3.2 父传子--数据传递(props)
3.3 父传子--配合循环
3.4 单向数据流
3.5 子传父--$emit
3.6 子传父--数据传递
3.7 子传父之sync(语法糖)
3.8 命名注意点
四、跨组件传值及多级传递
4.1 跨组件传值--EventBus
4.2 数据和方法的多级传递
五、组件插槽--v-slot指令
5.1 什么是v-slot指令?
5.2 使用 slot-scope 接收数据
六 、匿名插槽
七 、具名插槽
7.1 初识具名插槽
7.2 示例
八、作用域插槽
8.1 初识作用域插槽
8.2 其他应用场景
ii. 自定义组件内标签+内容
九、自定义指令
9.1 初识自定义指令
9.2 使用只定义指令进行传值
组件:可复用的vue实例, 通过封装其标签, 样式,和 JS代码
组件化:封装的思想,把页面上‘可重用的部分’封装为‘组件’,从而方便项目的开发和维护
例如:把一个很大的界面拆分为多个小的界面,每一个小的界面就是一个组件,将大界面拆分成小界面就是组件化
组件化的好处:
独立作用域
可以简化Vue实例代码
可以提高代码的复用性
每个组件都是一个独立的个体,代码里体现为一个独立的 .vue 文件
全局注册(全局组件)--main.js里进行如下配置:
在任何一个Vue实例控制的区域中都可以使用
import Vue from 'vue'
import 组件对象 from 'vue文件路径'
Vue.component('组件名', 组件对象)
<组件名>组件名>
局部注册(局部组件) -- 在需要用到组件的那个 .vue 文件里配置:
只能在自定义的那个Vue实例控制的区域中使用
import 组件对象 from 'vue文件路径'
export default {
components: {
"组件名": 组件对象
}
}
<组件名>组件名>
注意点:组件文件名/组件名 都以“大写”英文开头
运行:将组件标签换成对应封装的真实标签显示
在当前组件内标签都被随机的添加 data-v-hash值 的属性
css选择器都被添加 [data-v-hash值] 的属性选择器
Vue组件内样式, 只针对当前组件内标签生效如何做?
在style上添加scoped,webpack在打包的时候便会自动给标签添加data-v-hash值属性, 而且所有CSS的选择都会自动加上一个属性选择器
对于普通元素我们可以通过v-if来实现切换
对于组件我们也可以通过v-if来实现切换,因为组件的本质就是一个自定义元素
我是首页
我是详情页
我是个人中心页
什么是动态组件?
在同一个挂载点, 可以切换显示不同组件
如何使用动态组件?
vue内置的component组件, 配合is属性
如何切换?
改变is属性的值, 为要显示的组件名即可
通过v-if/v-else-if/v-else确实能够切换组件,但是在Vue中切换组件还有另一种更专业的方式,那就是动态组件:
根据数据的变化,结合 component 这个标签,来随时动态切换组件
步骤:
App.vue
1.动态 Dynamic 组件的使用
UserDynamic.vue
下面显示注册组件-动态切换:
UserName.vue
用户名:
密码:
UserInfo.vue
人生格言:
个人简介:
频繁的切换组件会导致组件频繁地创建和销毁,性能是不高的,那么如何避免呢?
component可以配合keep-alive来保存被隐藏组件隐藏之前的状态
如何进行组件缓存?
vue内置的keep-alive组件把要缓存的组件包起来
组件缓存好处?
不会频繁的创建和销毁组件, 页面更快呈现
keep-alive的用法:
参数:
include
- 字符串或正则表达式。只有名称匹配的组件会被缓存exclude
- 字符串或正则表达式。任何名称匹配的组件都不会被缓存max
- 数字。最多可以缓存多少组件实例
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和
相似,
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中
当组件在
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行
是用在其一个直属的子组件被开关的情形。如果你在其中有 v-for
则不会工作
include
和 exclude
prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
App.vue,
info.vue,
我是详情页
me.vue,
我是个人中心页
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块
为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义
Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染
App.vue
动态组件
AComponent.vue
AComponent
BComponent.vue
BComponent
{{message}}
ErrorComponent.vue
404
点击“切换”按钮后,
给组件添加动画和过去给元素添加动画一样,如果是单个组件就使用transition;如果是多个组件就使用transition-group
过渡动画注意点:
默认情况下进入动画和离开动画是同时执行的,如果想一个做完之后再做另一个,需要指定动画模式
同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。
out-in
:当前元素先进行过渡,完成之后新元素过渡进入。
.v-enter {
opacity: 0;
margin-left: 300px;
}
.v-enter-to {
opacity: 1;
}
.v-enter-active {
transition: all 3s;
}
.v-leave {
opacity: 1;
}
.v-leave-to {
opacity: 0;
}
.v-leave-active {
transition: all 3s;
margin-left: 300px;
}
我是详情页
我是个人中心页
在一个组件中又定义了其他组件就是父子组件,其实局部组件就是简单的父子组件,因为我们说过可以把Vue实例看作一个大组件
我们在Vue实例中定义了局部组件,就相当于在大组件里定义了小组件
谁被引入了谁就是“儿子”即子组件
如何定义其他的父子组件?
自定义组件中可以使用data,可以使用methods。当然自定义组件也可以使用components,所以我们也可以在自定义组件中再定义其他组件
注意:
子组件只能在定义它的父组件里面使用
App.vue
info.vue,
标题:口水鸡!!!
价格:50元
开业大酬宾,全场八折洛!
父子组件传递?
在Vue中子组件是不能访问父组件里的数据的,如果子组件想要访问父组件的数据,必须通过父组件传递
如何传递?
props:组件之间的数据交互
单向数据流:自上而下的传递
数组和对象的默认写法:default:[]-->工厂模式
数字和字符串可以直接写:default:0
info.vue,
标题:{{title}}
价格:{{price}}
{{intro}}
App.vue,
info.vue,
标题:{{title}}
价格:{{price}}
{{intro}}
App.vue,
循环使用组件注意事项?
每次循环, 变量和组件, 都是独立的
子组件内能改变, 父传入的数据吗? 能,但是不推荐
从父到子的数据流向, 叫单向数据流
子组件修改, 不通知父级, 造成数据不一致性
Vue规定props里的变量, 本身是只读的
info.vue,
标题:{{title}}
价格:{{price}}
{{intro}}
App.vue,
此时会报如下错误:
父子组件方法传递?
在Vue中子组件是不能访问父组件的方法的,如果子组件想访问父组件的方法,必须通过父组件传递
如何传递?
父组件内 <子组件 @自定义事件名="父methods里的函数名" />
子组件:this.$emit('自定义事件名', 值)
示例1:
App.vue,
我是父组件
-------------------------
info.vue,
我是子组件
示例2:
App.vue
info.vue
标题:{{title}}
价格:{{price}}
{{intro}}
什么时候使用子传父技术?
当子想要去改变父里的数据
子传父如何实现?
父组件内, 给组件@自定义事件="父methods函数"
子组件内, 恰当时机this.$emit('自定义事件名', 值)
如何传递?
既然我们可以将父组件的方法传递给子组件,我们可以在子组件里调用父组件中的方法,那么我们就可以在调用方法的时候给方法传递参数,传递的参数就是我们需要传递的数据
App.vue,
我是父组件
-------------------------
info.vue,
我是子组件
在子元素中修改父元素中的数据,可以使用.sync形式处理
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”
不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。
这也是为什么我们推荐以 update:myPropName
的模式触发事件取而代之
然后父组件可以监听那个事件并根据需要更新一个本地的数据 property
为了方便起见,我们为这种模式提供一个缩写,即 .sync
修饰符
注意:
带有 .sync
修饰符的 v-bind
不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’”
是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model
。
App.vue
P.vue
Parent
C.vue
Child
例如:注册时:myFather->使用时:my-father
例如:传递时:parent-name="name"->接收时:props:["parentName"]
例如:parent-say="say"->this.$emit("parent-say")
兄弟组件之间进行通信
两个没有任何引入关系的组件, 要如何互相通信呢?
什么时候需要 EventBus 技术:
当2个没有引用关系的组件之间需要通信传值
EventBus 技术的本质是什么:
空白 vue 对象,只负责 $on 注册事件 和 $emit 触发事件
$off -- 移除事件
MyProduct.vue 向 List.vue 传值
语法(步骤):
import Vue from 'vue'
// 导出空白的 vue 对象
export default new Vue()
App.vue,
MyProduct.vue,
标题:{{title}}
价格:{{price}}
{{intro}}
List.vue,
-
{{item.proname}}
{{item.proprice}}
在Vue中如果儿子想使用爷爷的数据,必须一层一层往下传递
在Vue中如果儿子想使用爷爷的方法,必须一层一层往下传递
爷爷组件
{{name}}
儿子组件
{{gfname}}
孙子组件
{{fname}}
通过 slot 标签, 让组件内可以接收不同的标签结构显示
v-slot指令是Vue2.6中用于替代slot属性的一个指令
在Vue2.6之前,我们通过slot属性告诉Vue当前内容填充到哪一个具名插槽
从Vue2.6开始,我们通过v-slot指令告诉Vue当前内容填充到哪一个具名插槽
语法口诀:
组件内用
注意点:
v-slot指令只能用在template标签上,可以使用#替代v-slot
App.vue
UseSlot.vue
案例:折叠面板
我是内容
寒雨连江夜入吴,
平明送客楚山孤。
洛阳亲友如相问,
一片冰心在玉壶。
Pannel.vue
芙蓉楼送辛渐
{{ isShow ? "收起" : "展开" }}
默认显示的内容
{{name}}
{{name}}
{{name}}
我是头部--{{names}}
作用域插槽方式获取:
我是默认数据--{{names}}
v-slot指令方式1方式获取(推荐):
我是默认数据--{{names}}
v-slot指令方式2方式获取(推荐):
我是默认数据--{{names}}
我是底部
我是追加的内容1
我是追加的内容2
我是追加的内容3
我是头部
我是默认数据
我是默认数据
我是底部
什么是具名插槽?
默认情况下有多少个匿名插槽,我们填充的数据就会被拷贝多少份,这导致了所有插槽中填充的内容都是一样的,为了解决这个问题,因此可以使用具名插槽
具名插槽的使用:
通过slot的name属性给插槽指定名称以此来进行区分
在使用时可以通过slot="name"方式,指定当前内容用于替换哪一个插槽
注意点:
如果没有指定要替换哪个插槽中的内容,则不会被替换
slot属性在Ve2.6中已经废弃,Vue2.6之后使用v-slot指令替代slot属性
v-slot: 指令只能用在template标签上,可以使用#替代v-slot:
App.vue
UseSlot.vue
案例:折叠面板
图片
我是内容
芙蓉楼送辛渐
寒雨连江夜入吴,
平明送客楚山孤。
洛阳亲友如相问,
一片冰心在玉壶。
Pannel.vue
{{ isShow ? "收起" : "展开" }}
默认显示的内容
使用插槽时, 想使用组件内的变量?
什么是作用域插槽?
作用域插槽就是带数据的插槽,就是让父组件填充子组件插槽内容时也能使用子组件的数据
如何使用作用域插槽
在slot中通过v-bind:数据名称="数据名称"方式暴露数据
在父组件中通过接收数据
在父组件的中通过 作用域名称.数据名称 方式使用数据
使用插槽时,需要使用组件内的变量
App.vue
Pannel.vue
{{ isShow ? "收起" : "展开" }}
{{defaultObj.defaultOne}}
UseSlot.vue
案例:折叠面板
{{name.row.defaultTwo}}
i. 子组件提供数据,父组件决定如何渲染
当子组件要渲染的内容由父组件决定的时候,就可以通过作用域插槽来实现
{{name}}
我是头部--{{names}}
我是默认数据--{{names}}
我是底部
让组件内的标签可以随意地定义和数据的使用
App.vue
UseTable.vue
MyTable.vue
序号
姓名
年龄
头像
{{index + 1}}
{{obj.name}}
{{obj.age}}
{{obj.headImgUrl}}
a. 全局注册:
b. 局部注册:
main.js
// 全局指令
Vue.directive('gfocus', {
inserted(el){
// console.log(el);
el.focus() // 触发标签的事件方法
}
})
App.vue
UseDirective.vue
注意点:
inserted() 会在指令所在的标签被插入到网页上时才触发
定义color指令-传入一个颜色, 给标签设置文字颜色
App.vue
UseDirective.vue
修改文字的颜色1
修改文字的颜色2