Vue 04Day Knowledge Point
一.组件进阶
一.ref 和 $refs
作用:利用 ref 和 $refs 可以用于 获取 dom 元素, 或者组件实例
1.获取原生DOM标签
添加ref属性,获取目标标签
2.通过ref属性获取组件对象
通过 this.$refs 获取组件对象, 可调用组件对象里方法等
二.$nextTick
1.$nextTick的学习
需求:点击改data的数据, 获取原生DOM内容
1.创建标签显示数据
<p ref = "a">数字:{{count}}</p>
<button @click="btn">点击加一</button>
2.点击+1, 马上获取原生DOM内容
methods: {
btn(){
this.count++;
console.log(this.$refs.a.innerHTML);
}
}
$nextTick:等DOM更新后, 才会触发执行此方法里的函数体
data改变,更新DOM是异步的,我们可以运用this.$nextTick里的函数体获取到更新后的DOM
2.$nextTick小案例
需求:点击按钮自身隐藏, 出现输入框并马上处于激活状态
注意: 一定要用v-if来写 (保证DOM异步更新前获取不到输入框, 可以体现$nextTick的价值)
<template>
<!-- 准备好input 和 按钮 -->
<!-- 按钮点击 会显示 input (点击按钮消失,显示input,并显示focus焦点) -->
<!-- 给按钮绑定一个点击事件 @click = "searchFn" 然后在methods中 调用事件函数
因为input 是进行隐藏 我们使用v-if 按钮则运用v-else 进行一个切换
在点击事件函数中 进行v-if="show" 的取反 单点击按钮 按钮隐藏 input框显示
-->
<!-- 获取焦点,就要找dom 给input 添加一个ref 获取dom中的focus
this.$refs.inp.focus()
因为他是异步 所以需要用
this.$nextTick(()=>{
console.log(this.$refs.inp.focus());
});
-->
<div>
<input type="text" placeholder="输入搜索的关键字" v-if="show" ref="inp" />
<button v-else @click="searchFn">点击搜索</button>
</div>
</template>
<script>
export default {
data(){
return{
show:false,
}
},
methods:{
searchFn(){
this.show = !this.show;
this.$nextTick(()=>{
console.log(this.$refs.inp.focus());
// console.log(this.$refs.inp);
});
}
}
}
</script>
<style>
</style>
三.dynamic 动态组件
1.基本概念
动态组件:可以改变的组件
动态组件可以解决多组件同一个位置,切换显示的需求
基本语法:
1.compontent 组件(位置) + is属性(哪个组件)
2.修改is属性绑定的值 => 切换组件
3.动态组件切换的时候会销毁
4.可以缓存 keep-alive
2.动态组件点击切换小案例
当点击指定的按钮就会切换相应内容
<template>
<div>
<button @click="name = 'little-cat'">小猫</button>
<button @click="name = 'little-dog'">小狗</button>
<button @click="name = 'little-pig'">小猪</button>
<component :is="name"/>
</div>
</template>
<script>
import Cat from './components/little-cat.vue';
import Dog from './components/little-dog.vue';
import Pig from './components/little-pig.vue';
export default {
data(){
return{
name:'little-cat'
}
},
components:{
'little-cat':Cat,
'little-dog':Dog,
'little-pig':Pig,
}
}
</script>
<style>
</style>
三个子组件都是按照以下代码操作(代码一样,只放一份)
<template>
//将小猫改成其他名称 分别放入对于的子组件即可
<div><h1>小猫</h1></div>
</template>
<script>
export default {}
</script>
<style>
</style>
二.自定义指令
1.自定义指令
自定义指令即自己定义的指令,封装dom操作,扩展额外功能
有局部注册 和 全部注册
需求:当页面加载时,让元素将获得焦点
局部注册
<template>
<!-- 当我们需要封装dom 扩展额外功能的时候我们就使用自定义指令 -->
<div>
<h1 v-color v-backgroundColor v-bold>你好</h1>
</div>
</template>
<script>
export default {
// 局部注册
directives:{
"color":{
inserted(dom){
dom.style.color = 'red';
}
},
"backgroundColor":{
inserted(dom){
dom.style.backgroundColor = 'yellow';
}
}
}
}
</script>
<style>
</style>
全局注册
// 全局注册
// Vue.component("组件标签名",组件对象);
// 全局注册 ——自定义属性
Vue.directive("bold",{
"inserted"(dom){
dom.style.fontWeight = 'bold';
}
})
2.自定义指令的值
语法:在绑定指令时,可以通过“等号”的形式为指令绑定具体的参数值
通过 binding.value 可以拿到指令值,指令值修改会触发 update
<template>
<!-- 当我们需要封装dom 扩展额外功能的时候我们就使用自定义指令 -->
<div>
<!-- 给指定添加颜色 可以 但是不能直接添加 要在数据中传递颜色 然后binding binding.value-->
<h1 v-color='red' v-bold>你好</h1>
<h1 v-color='yellow' v-bold>你好</h1>
<h1 v-color='blue' v-bold>你好</h1>
<!-- 直接在点击事件赋值是不可以的 需要更新它 -->
<button @click="red = 'black'">把红色变成黑色</button>
</div>
</template>
<script>
export default {
data(){
return{
red:'red',
yellow:'yellow',
blue:'blue',
}
},
// 局部注册
directives:{
"color":{
inserted(dom,binding){
console.log("指令参数",binding);
dom.style.color = 'red';
// 这里的dom就是我们指令所在的标签的dom 修改dom颜色
dom.style.color = binding.value;
},
// update 会在指令的值v-指令 = "变量" 变量变化时候触发
update(dom,binding){
dom.style.color = binding.value;
}
},
"backgroundColor":{
inserted(dom){
dom.style.backgroundColor = 'yellow';
}
}
}
}
</script>
<style>
</style>
三.插槽
1.默认插槽
插槽:组件内部分内容允许外部传入
组件的内容部分,不希望写死,希望能使用的时候自定义,使用插槽。
<template>
<div class="container">
<category-category title="美食" :list="foods">
<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
</category-category>
<category-category title="游戏" :list="games">
<ul>
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
</category-category>
<category-category title="电影" :list="films">
<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
</category-category>
</div>
</template>
<script>
import category from './components/category.-cate.vue'
export default {
components:{
'category-category':category
},
data(){
return{
foods:['火锅','烧烤','汉堡','牛排'],
games:['lol','穿越火线','QQ飞车','红色警戒'],
films:['《蜡笔小新》','《名侦探柯南》','《赌侠》','《赌圣》']
}
}
}
</script>
<style scoped>
.container{
display: flex;
justify-content: space-around;
}
img{
width: 100%;
}
video{
width: 100%;
}
</style>
<template>
<div class="category">
<h3>{{title}}分类</h3>
<!-- 定义个插槽 (挖个坑 等着组件的使用者进行填充) -->
<slot>默认值,当使用者没有传递具体结构,我就出现</slot>
<!-- <ul>
<li v-for="(item,index) in list" :key="index">{{item}}</li>
</ul> -->
<!-- http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 -->
</div>
</template>
<script>
export default {
// props:['list','title']
props:['title']
}
</script>
<style>
.category{
background-color: skyblue;
width: 200px;
height: 300px;
}
h3{
text-align: center;
background-color: orange;
}
</style>
2.具名插槽
<template>
<div class="container">
<category-category title="美食" :list="foods">
<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
<a slot="footer" href="http://baidu.com">更多美食</a>
</category-category>
<category-category title="游戏" :list="games">
<ul slot="center">
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ul>
<div class="foot" slot="footer">
<a href="http://baidu.com">单机游戏</a>
<a href="http://baidu.com">网络游戏</a>
</div>
</category-category>
<category-category title="电影" :list="films">
<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
<!-- <template slot="footer"> -->
<template v-slot:footer>
<div class="foot">
<a href="http://baidu.com">经典</a>
<a href="http://baidu.com">热门</a>
<a href="http://baidu.com">推荐</a>
</div>
<h4>欢迎前来观看</h4>
</template>
</category-category>
</div>
</template>
<script>
import category from './components/category.-cate.vue'
export default {
components:{
'category-category':category
},
data(){
return{
foods:['火锅','烧烤','汉堡','牛排'],
games:['lol','穿越火线','QQ飞车','红色警戒'],
films:['《蜡笔小新》','《名侦探柯南》','《赌侠》','《赌圣》']
}
}
}
</script>
<style scoped>
.container,.foot{
display: flex;
justify-content: space-around;
}
img{
width: 100%;
}
video{
width: 100%;
}
h4{
text-align: center;
}
</style>
<template>
<div class="category">
<h3>{{title}}分类</h3>
<!-- 定义个插槽 (挖个坑 等着组件的使用者进行填充) -->
<slot name="center">默认值,当使用者没有传递具体结构,我就出现1</slot>
<slot name="footer">默认值,当使用者没有传递具体结构,我就出现2</slot>
<!-- <ul>
<li v-for="(item,index) in list" :key="index">{{item}}</li>
</ul> -->
<!-- http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 -->
</div>
</template>
<script>
export default {
// props:['list','title']
props:['title']
}
</script>
<style>
.category{
background-color: skyblue;
width: 200px;
height: 300px;
}
h3{
text-align: center;
background-color: orange;
}
</style>
3.作用域插槽
<template>
<div class="container">
<category-category title="游戏" >
<template scope="obj">
<ul>
<li v-for="(g,index) in obj.games" :key="index">{{g}}</li>
</ul>
</template>
</category-category>
<category-category title="游戏" >
<template scope="obj">
<ol>
<li style="color:red" v-for="(g,index) in obj.games" :key="index">{{g}}</li>
</ol>
</template>
</category-category>
<category-category title="游戏">
<template scope="obj">
<h4 v-for="(g,index) in obj.games" :key="index">{{g}}</h4>
</template>
</category-category>
</div>
</template>
<script>
import category from './components/category.-cate.vue'
export default {
components:{
'category-category':category
},
}
</script>
<style scoped>
.container,.foot{
display: flex;
justify-content: space-around;
}
img{
width: 100%;
}
video{
width: 100%;
}
h4{
text-align: center;
}
</style>
<template>
<div class="category">
<h3>{{title}}分类</h3>
<!-- <slot >默认值,当使用者没有传递具体结构,我就出现1</slot> -->
<slot :games="games">我是默认的一些内容</slot>
</div>
</template>
<script>
export default {
props:['title'],
data(){
return{
games:['lol','穿越火线','QQ飞车','红色警戒'],
}
}
}
</script>
<style>
.category{
background-color: skyblue;
width: 200px;
height: 300px;
}
h3{
text-align: center;
background-color: orange;
}
</style>
4.插槽传参
匿名插槽传参
<template>
<div>
<niming-slot v-slot="obj">
<img :src="obj.zidingyi.url" alt="">
<h1>{{obj.zidingyi.name}}</h1>
<h1>{{obj.zidingyi.age}}</h1>
</niming-slot>
</div>
</template>
<script>
import NingMing from "./components/niming-slot.vue";
export default {
components:{
"niming-slot":NingMing,
}
}
</script>
<style>
</style>
<template>
<div>
<slot :zidingyi="user"></slot>
</div>
</template>
<script>
export default {
data(){
return{
user:{
name:'小明',
age:18, url:"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1113%2F041620104229%2F200416104229-8-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659665716&t=a7f983f36e9540d91b49a362a93540f3",
}
}
}
}
</script>
<style>
</style>
具名插槽传参(需要多个插槽)
<template>
<div>
<personal-info>
<template #header="obj">
<h1>{{obj.headerheader}}</h1>
</template>
<template #tbody="obj">
<h1>{{obj.tbodytbody}}</h1>
</template>
<template #footer="obj">
<img :src="obj.tupian" alt="">
</template>
</personal-info>
</div>
</template>
<script>
import PersonnalInfo from "./components/personal-info.vue"
export default {
components:{
"personal-info":PersonnalInfo,
}
}
</script>
<style>
</style>
<template>
<div>
<slot name="header" :headerheader="user.name"></slot>
<slot name="tbody" :tbodytbody="user.age"></slot>
<slot name="footer" :tupian="user.url"></slot>
</div>
</template>
<script>
export default {
data(){
return{
user:{
name:'小明',
age:18,
url:"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1113%2F041620104229%2F200416104229-8-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659665716&t=a7f983f36e9540d91b49a362a93540f3",
}
}
}
}
</script>
<style>
</style>