目录
3.2.2 私有自定义指令---通过binding.value获取指令绑定的值
一、动态组件
1.1 什么是动态组件
动态组件指的是动态切换组件的显示与隐藏
1.2 动态切换组件的显示与隐藏
vue提供了一个内置的<component>组件,专门用来实现动态组件的渲染,控制显示页面的属性是is。示例代码如下:
<component :is="shownam"></component>
<template>
<div id="app">
<h1>App.vue</h1>
<div>
<button @click="shownam = 'Left'">展示Left</button>
<button @click="shownam = 'Right'">展示Right</button>
</div>
<div>
<!-- is属性用来控制显示的组件 -->
<component :is="shownam"></component>
</div>
</div>
</template>
<script>
import Left from '@/components/left.vue'
import Right from '@/components/right.vue'
export default {
components: {
Left,Right
},
data() {
return {
shownam: ''
}
}
}
</script>
<style lang="less" scoped>
</style>
实现效果如下:点击展示Left按钮,展示Left.vue页面。电视展示Right按钮,展示Right.vue页面 .效果类似于移动端App的底端Tabbar
1.3 使用keep-alive保持状态
问题描述:若在left.vue页面中添加加1的按钮,加到N后点击展示Right按钮,再点击展示left按钮。此时数字又变成了1。
解决:采用keep-alive解决上述问题。将要保持的标签外部加keep-alive标签即可
注: keep-alive可以把内部的组件进行缓存,而不是销毁组件
1.4 keep-alive对应的生命周期
当组件被缓存时,会自动触发组件的deactivated生命周期函数
当组件被激活时,会自动触发组件的activated生命周期函数
当组件第一次被创建的时候,既会执行created生命周期,也会执行activated生命周期
但是,当组件被激活的时候,只会触发activated生命周期,不再触发created生命周期,因为组件没有被重新创建。
注:只有加了keep-alive标签的,才有deactivated和activated生命周期函数。
注:生命周期函数应该在子页面中编写
app.vue:
<template>
<div id="app">
<h1>App.vue</h1>
<div>
<button @click="shownam = 'Left'">展示Left</button>
<button @click="shownam = 'Right'">展示Right</button>
</div>
<div>
<!-- is属性用来控制显示的组件 -->
<keep-alive>
<component :is="shownam"></component>
</keep-alive>
</div>
</div>
</template>
<script>
import Left from '@/components/left.vue'
import Right from '@/components/right.vue'
export default {
components: {
Left,Right
},
data() {
return {
shownam: ''
}
}
}
</script>
<style lang="less" scoped>
</style>
left.vue:
<template>
<div id="left">
<h3>LEFT组件-----{{ count }}</h3>
<button @click="count += 1">+1</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
created() {
console.log('left---created生命周期函数')
},
activated() {
console.log('left---activated生命周期函数')
},
deactivated() {
console.log('left---deactivated生命周期函数')
},
}
</script>
<style lang="less" scoped>
#left {
background-color:rgb(111, 0, 255);
// width: 50%;
// height: 400px;
}
</style>
1.5 keep-alive的include属性
include属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间用英文逗号分隔
exclude用来指定哪些不被缓存。include和exclude不能同时使用
1.6 组件注册名称和组件声明时name的区别
组件的注册名称(App.vue):
组件声明时的Name(Left.vue)
当提供了name属性后,组件的名称就是name属性值。
区别:(1)组件的注册名称的主要应用场景是:以标签的形式,把注释好的组件,渲染和使用到页面结构中。
(2)组件声明时候的“name”名称的主要应用场景,结合<keep-alive>标签实现组件缓存功能,以及在调试工具中看到组件的name名称
二、插槽
2.1 什么是插槽
插槽(Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望用户指定的内容定义为插槽。
插槽使用示例:
(1)left.vue中用<slot>标签占位,声明一个插槽
(2) App.vue中用p标签填充slot区域
效果如下:
2.2 v-slot
2.2.1 v-slot的基本使用
注:vue官网规定,每一个slot插槽,都要有一个name名称,如果省略了slot的name属性,则有一个默认的名称叫做default。
<slot name="default"></slot>
默认情况下,在使用组件的时候,提供的内容都会填充到名字为default的插槽之中
如果要把内容填充到指定名称的插槽中,需要使用v-slot这个指令。v-slot:插槽名称
v-slot不能直接用在元素身上,必须用在template标签上。
template只是一个虚拟标签,不会被渲染成HTML元素
v-slot使用示例如下:
(1)left.vue中定义插槽,名称为test
(2)app.vue中使用插槽,通过v-slot 指定插槽名称
2.2.2 v-slot的简写是#
2.2.3 插槽的默认内容
若想指定默认内容。则操作如下:
此时若注释app.vue中传入的内容,页面显示的是“slot的默认内容”。若不去除,则显示的是app.vue中指定的插槽内容。
2.3 具名插槽
具名插槽,顾名思义,就是给每个插槽都起对应的名称,方便用户后期渲染,示例如下:
(1)App.vue
<template>
<div id="app">
<h1>App.vue</h1>
<div>
<Article>
<template #title>
<h3>一首诗</h3>
</template>
<template #content>
<div>
<p>大海</p>
<p>土地</p>
</div>
</template>
<template #author>
<div>作者:xxxx</div>
</template>
</Article>
</div>
<div>
</div>
</div>
</template>
<script>
import Article from '@/components/Article.vue'
export default {
components: {
Left,
Right,
Article
},
}
</script>
<style lang="less" scoped>
</style>
(2)Article.vue
<template>
<div class="Article-container">
<!-- 文章标题 -->
<div class="header-box">
<slot name="title"></slot>
</div>
<!-- 文章内容 -->
<div class="content-box">
<slot name="content"></slot>
</div>
<!-- 文章作者 -->
<div class="footer-box">
<slot name="author"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'Article'
}
</script>
<style lang="less" scoped>
.Article-container {
>div {
min-height: 150px;
}
.header-box {
background-color: pink;
}
.content-box {
background-color: powderblue;
}
.footer-box {
background-color: sandybrown;
}
}
</style>
效果如下:
2.4 作用域插槽
2.4.1 作用域插槽的基本用法
作用域插槽:在封装组件时,为预留的<slot>提供属性对应的值,这种用法称为“作用域插槽”
2.4.2 作用域插槽的解构赋值
Article.vue:
<template>
<div class="Article-container">
<!-- 文章标题 -->
<div class="header-box">
<slot name="title"></slot>
</div>
<!-- 文章内容 -->
<div class="content-box">
<slot name="content" msg="hello" :user="userinfo"></slot>
</div>
<!-- 文章作者 -->
<div class="footer-box">
<slot name="author"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'Article',
data() {
return {
userinfo: {
name: 'zs',
age: 18
}
}
}
}
</script>
<style lang="less" scoped>
</style>
App.vue:
<template>
<div id="app">
<h1>App.vue</h1>
<div>
<Article>
<template #title>
<h3>一首诗</h3>
</template>
<template #content="scope">
<div>
<p>大海</p>
<p>土地</p>
<p>{{scope.user}}</p>
</div>
</template>
<template #author>
<div>作者:xxxx</div>
</template>
</Article>
</div>
<div>
</div>
</div>
</template>
<script>
import Left from '@/components/left.vue'
import Right from '@/components/right.vue'
import Article from '@/components/Article.vue'
export default {
components: {
Left,
Right,
Article
},
}
</script>
<style lang="less" scoped>
</style>
如上,Article.vue中传入了一个对象,在Article.vue设置属性为userinfo对象
App.vue中接收:
也可采用解构赋值:
2.4.3 基于插槽改造购物车案例
利用插槽实现数量加减的功能:
在Goods.vue中添加<slot>
(2)App.vue中渲染插槽内容
此时页面效果实现,但是点击加减无反应,且原始的数量值都是1
采用插槽后,Counter.vue属于App.vue的子组件,而不是孙子组件,不需要再像之前一样,借助Goods.vue传值。
(1)默认值属于父向子传值,采用自定义属性的方法。
(2)点击+ / - 属于子向父传值,采用自定义方法。代码如下:
改造后的Counter.vue
<template>
<div class="counter-container">
<!-- 减1的按钮 -->
<!-- 执行值减1,并将值传递给组件App.vue,此处采用的是eventBus -->
<button class="btn" @click="minus">-</button>
<!-- 购买的数量 -->
<!-- 购买数量是父组件Goods组件传递过来的 -->
<span class="number-box">{{ count }}</span>
<!-- 加1的按钮,并将值传递给组件App.vue,此处采用的是eventBus-->
<button class="btn" @click="add">+</button>
</div>
</template>
<script>
import bus from '@/components/eventBus.js'
export default {
props: {
// 接收商品的id值,将来使用eventBus方案,把数量传递到App.vue的时候,需要通知App组件,
// 更新的是哪个商品的数量
id: {
type: Number,
required: true
},
// 购买的数量,父组件App.vue赋值
count: {
default: 1,
type: Number
}
},
methods: {
minus() {
// 要发送App的数据格式为{id,value}
// 减去的时候等于0的时候,不能再点
if(this.count - 1 === 0) return
this.$emit('send',this.count - 1)
},
add() {
this.$emit('send',this.count + 1)
}
}
}
</script>
<style lang="less" scoped>
.number-box {
min-width: 30px;
text-align: center;
margin: 0 5px;
}
</style>
App.vue:
methods中定义getNewNum方法,将传过来的值,赋值给对应id项
三、自定义指令
3.1 什么是自定义指令
vue官方提供了v-text,v-for,v-if等常用的指令,还允许开发者自定义指令。
3.2 自定义指令分类
(1)私有自定义指令
(2)全局自定义指令
3.2.1 私有自定义指令----基本使用
在每个vue组件中,可以在directives节点下声明私有自定义指令,示例代码如下:
(1)定义:在directives节点下定义自定义指令
(2)使用:使用时在自定义指令前加v-
3.2.2 私有自定义指令---通过binding.value获取指令绑定的值
若想在v-color后加属性值,则directives中需要借助binding形参,binding.value就是v-color获取到的值,用法如下:
3.2.3 私有自定义指令---update函数
bind函数只调用一次:当指令第一次绑定到元素时调用,当DOM更新时bind函数不会被触发。update函数会在每次DOM更新时被调用。示例代码如下:
在App.vue中创建按钮,更改color的值,更改后color的值更改成功,但页面无更新。原因是bind函数只在第一次绑定元素时生效,后期值更新后不生效。需要借助update函数实现:
注:bind和update函数都需要,bing函数负责第一次绑定元素,update负责后期更新
3.3 自定义指令----函数简写(注意前提)
若bind和update函数内部的语句一样,可简写:
3.4 全局自定义指令
全局共享自定义指令通过Vue.directive()在main.js中声明,示例代码如下:
参数1:字符串,表示全局自定义指令的名字
参数2:对象,用来接收指令的参数值
可简写为:
注:过滤器和自定义指令一般都全局定义!!!!
小知识
main.js中这个配置用来定义控制台是否展示提示 :
提示在上线前将模式修改为production,仅为提示,无实际意义,默认为false