【vue2】组件进阶与插槽详解

news/2024/11/9 9:23:11/

1d43f75f092a4050a8ce31e2d85f6868.gif

🥳博       主:初映CY的前说(前端领域)

🌞个人信条:想要变成得到,中间还有做到!

🤘本文核心:v-modedl表单双向绑定、ref|$ref操作dom、dynamic动态组件、$nextTick同步、匿名插槽、具名插槽、作用域插槽


目录(文末有给大家准备好的Xmind思维导图)

一、组件进阶

1.v-model语法

2.ref与$ref语法

3.dynamic动态组件

4.this.$nextTick()

二、匿名|具名|作用域插槽

插槽概念:

1.匿名插槽

2.具名插槽

3.作用域插槽


 

一、组件进阶

1.v-model语法

v-model指令我们的一个初印象就是表单数据实现绑定双向,一修改同步修改,那么本质是什么?

博主认为v-mode语法本质上是简化了书写操作。触发v-model需要满足两个条件的(标红部分是语法规定部分不可自定义)

  1. data中数据变化,表单的值也会变化  :value="data中的属性名" 
  2. 表单的值发生变化,data中的数据也会变化  @input="data中的属性名=$event.target.value"

当满足了就可直接写上v-model="我们data中的属性名"

举个例子:

<template><div><h1>根组件App.vue</h1><!-- 1.v-model = "msg"(1)data中的数据变化,表单的值也会变化     :value="msg"(2)表单的值发生变化,data中的数据也会变化  @input="msg=$event.target.value"--><input type="text" v-model="msg" /><hr /><!-- 这种写法与上面写法功能一致 --><input type="text" :value="msg" @input="msg = $event.target.value" /><hr /><!-- 这种写法也与上面写法一致 --><input type="text" :value="msg" @input="doInput" /><hr /></div>
</template><script>
export default {data() {return {msg: ""};},methods: {doInput(e) {this.msg = e.target.value;}}
};
</script><style>
</style>

 效果演示:

69d4096addb944f5bbcf0072f368acc3.gif

 可见:当我们直接用v-model="属性名“这种方法写简化了书写的难度达到了同样的效果。


2.ref与$ref语法

这个语法可使用操作dom元素。每个 vue 的组件实例上,都包含一个$refs 对象,里面存储着对应的DOM 元素或组件的引用。

注意点:

当ref="自定义名"是写在组件身上就可以得到该对象实例vue

绑定是ref,调用是$refs

1.绑定dom写法:<标签 ref="自定义名"></标签>

    <div ref="aaa" class="box"></div><input ref="bbb" type="text"><my-goods ref="ccc" ></my-goods>

2.调用dom写的:this.$refs.自定义属性名 

console.log(this.$refs.aaa);
console.log(this.$refs.bbb);
console.log(this.$refs.ccc);
// 调用子组件方法
console.log(this.$refs.ccc.doClick());//都包含一个$refs 对象因此可已获取标签里面的方法(组件)

参考下面这个例子:

父组件:App.vue

<template><div><h1>我是父组件</h1><button @click="onAdd">点我查看ref打印的啥</button><div ref="aaa" class="box"></div><input ref="bbb" type="text"><my-goods ref="ccc" ></my-goods></div>
</template><script>
import MyGoods from '@/components/MyGoods.vue'
export default {components: { MyGoods },data() {return {}},methods: {onAdd() {console.log(this);console.log(this.$refs.aaa);console.log(this.$refs.bbb);console.log(this.$refs.ccc);// 调用子组件方法console.log(this.$refs.ccc.doClick());},}
}
</script><style></style>

子组件:MyGoods.vue

<template><div><p>商品名称:小米</p><p>商品价格:{{ price }}</p><button @click="doClick">点我购买</button></div>
</template><script>
export default {
props:{value:Number
},
data(){return{price:'999'}
},methods: {doClick() {console.log("点击了购买");return 0//当不写的时候调用了方法没有return会提示undefinded}
}
}
</script><style></style>

实现效果:

b4364b538951416599c1a72c872dfce7.png


3.dynamic动态组件

什么是动态组件: 让多个组件使用同一个挂载点并动态切换,这就是动态组件。

通过设置组件名,让一个挂载点可以切换不同的组件。

语法格式:

 <component :is="组件名"></component>

举个例子:

父组件App.vue

<template><div><h1>我是父组件</h1><button @click="comName='login'">登录</button><button @click="comName='user'">信息</button><component :is="comName"></component></div>
</template>
<script>
import login from '@/components/login.vue'
import user from '@/components/user.vue'export default {components: { login, user },data() {return {comName:"user"}
}
}
</script><style></style>

子组件 user.vue

<template><div><p>我是个人信息组件</p></div>
</template>
<script>
export default {
name:"user"
}
</script>
<style>
</style>

子组件 login.vue

<template><div><p>我是登录组件</p></div>
</template>
<script>
export default {
name:"login"
}
</script>
<style>
</style>

实现效果:

084af1e98c4047a6b813efd2229574dd.gif

 可以看到我们通过<component :is="组件名">找到相应的标签运行


4.this.$nextTick()

是用来将我们vue的异步操作进行放在页面dom渲染前面。想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()

上个例子:

<template><div><h1>我是父组件</h1><input type="text" v-if="flag" ref="input"><button v-else @click="doClick">点我开始输入</button></div>
</template><script>
export default {data() {return {flag: false}},methods: {doClick() {this.flag = truethis.$nextTick(() => {//一定要箭头函数,因为箭头函数的this指向上一层作用域与原本的this是同一个this.$refs.input.focus()})}}
}
</script><style></style>

 实现的效果:

7c40b45c422d4fb79ff5d09a21a1c7fa.gif

当 this.flag = true执行完成之后页面应该是执行渲染在页面的操作,但是我们的 vue是异步的微任务(Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新),渲染的时候找不到ref="input"这个dom就会报错,因此需要就用  this.$nextTick来将需要的操作放在渲染之前。

fec7f266506f48c0ab759ebe23784fc5.png

 可看上图:当我写在外面的时候就会报错。

原理:vue操作dom是异步的操作,如果需要同步显示出来需要利用this.$nextTick()将异步操作提前放在dom树更新前


二、匿名|具名|作用域插槽

插槽概念:

  • slot相当于是组件里面的一个内置的开关,打开了这个开关就可以在复用组件的同时修改单个组件中的HTML的结构。
  • 用来解决组件复用的同时可以对单个组件进行修改操作,让组件变得更加灵活

1.匿名插槽

我们在父中调用子组件,在复用组件的同时修改单个组件不受影响

插槽书写结构:   

父传:<子组件名>HTML结构</子组件名>

子收: <slot>此处写默认值</slot>

我们一起来看看这个例子:

父组件:App01(匿名插槽).vue

<template><div><h1>我是父组件</h1><goods><button>已下单</button></goods><goods></goods><goods ><button disabled>已卖完</button></goods><goods><a href="#">点我跳转</a></goods></div>
</template><script>
import goods from '@/components/goods.vue'
export default {
components:{goods}
}
</script><style></style>

 子组件:goods.vue

<template><div class="son"><h3>我是子组件</h3><h4>商品名称</h4><!-- slot相当于是一个开关,打开了这个开关就可以插入想要的值从父传 HTML的结构 --><slot>我是默认的插槽</slot></div>
</template><script>
export default {name: "goods",data() {return {}}
}
</script><style scoped>
.son {border: 1px solid red;
}
</style>

我们先看下我们的实现效果:

f252bd2e1afc4300b96352711ab278a6.png

 可以看出来,我们的<goods></goods>调用了四次,我们在父中的值传到子中的都不一样,页面也根据我们所想的展示出来了不同的组件。


2.具名插槽

使用多个slot实现精准的传递多个位置的插槽给子组件 ,写的时候必须在<template></template>中

具名插槽书写结构: 

父传:

<组件名><template v-slot:自定义名><h2>HTML结构</h2></template></组件名>

子收:

      <div ><slot name="自定义插槽名">插槽默认值</slot></div>

我们一起来看看这个例子:

父组件:App02(具名插槽).vue

<template><div><h1>我是父组件</h1><cell><template v-slot:title><h2>I am Tittle</h2></template><template v-slot:content><i>I am goodsInfo</i></template><template v-slot:right><i>My position</i></template></cell></div>
</template><script>
import cell from '@/components/cell.vue'export default {
components:{cell}
}</script><style></style>

 子组件:cell.vue

<template><div class="cell">
<!-- 具名插槽使用:1.在子组件钟使用 slot+name确定组件的作用域2.在父组件钟用template 接收 使用v-slot:name传递--><div class="title" ><slot name="title">我是默认标题</slot></div><div class="content" ><slot name="content"> 我是文本信息</slot></div><div class="right" ><slot name="right">我是右侧信息</slot></div></div>
</template><script>
export default {}
</script><style>.cell{border: 1px solid #f00;height: 60px;padding: 10px;position: relative;}.title{float: left;line-height: 1px;}.content{position: absolute;bottom: 10px;left: 10px;}.right{float: right;}
</style>

 实现效果:

acc170858c1e44a285f80763ab417c71.png

 通过这个例子,我们可以看到,我们具名比匿名插槽多了一个精准定位的功能。

 

3.作用域插槽

父组件可根据子组件传过来的插槽数据来进行不同的方式展现和填充插槽内容

具名插槽书写结构: 

子组件传递:

    <slot name="自定义插槽名" >HTML结构</slot>

父组件接收:(注意接收的是一个对象)

    <组件名 父传值属性><template v-slot="{一个对象}">HTML属性</template></组件名>

来个例子:

父组件:App03(作用域插槽).vue

<template><div><!-- 1.匿名插槽:父组件传递 单个HTML结构 给子组件父传:<子组件>HTML结构</子组件>子收:<slot>默认HTML结构</slot>2.具名插槽:父组件传递 多个HTML结构 给子组件父传:<子组件><template #插槽名>HTML结构</template></子组件> 子收:<slot name="插槽名">默认HTML结构</slot>3.作用域插槽:子组件传递数据给父组件子传:<slot 属性名="属性值">默认HTML结构</slot>父收:<子组件><template v-slot="对象名">HTML结构</template></子组件> --><!-- (具名插槽 + 作用域插槽)组合写法:#插槽名 = "对象名" --><h1>父组件</h1><student></student><h3>删除功能</h3><student :arr="list1"><template v-slot="{ $index }"><button @click="list1.splice($index, 1)">删除</button></template></student><h3>头像功能</h3><student :arr="list2"><template v-slot="{ row }"><img :src="row.headImgUrl" alt="" /></template></student></div>
</template><script>
import student from "./components/student.vue";
export default {components: { student },data() {return {list1: [{id: "13575",name: "小传同学",age: 18,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",},{id: "62408",name: "小黑同学",age: 25,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",},{id: "73969",name: "智慧同学",age: 21,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",},],list2: [{id: "13575",name: "传同学",age: 8,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",},{id: "62408",name: "黑同学",age: 5,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",},{id: "73969",name: "慧同学",age: 1,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",},],};},
};
</script><style>
</style>

子组件: student.vue

<template><div><slot name="title" >修改</slot><table border="1"><thead><tr><th>序号</th><th>姓名</th><th>年龄</th><th>头像</th></tr></thead><tbody><tr v-for="(item,index) in arr" :key="item.id"><td>{{ index+1 }}</td><td>{{ item.name }}</td><td>{{ item.age }}</td><td><slot :row="item" :$index="index"></slot></td></tr></tbody></table></div>
</template><script>
export default {props: { arr: Array },data() {return {}}
}
</script><style scoped>
table {margin-top: 20px;
}td {height: 60px;
}img {height: 90%;
}
</style>

效果如下:a1b748652e1c4c3093024bf94e2b0906.gif

 可以看见,我们复用的三个student的组件都分别实现了不同的效果,第一个因为我没有将父组件中的arr传进去,因此arr提示undefin,后面两个组件分别实现了不同的功能。对比具名插槽,作用域插槽实现了

总结匿名|具名|作用域函数:

匿名插槽:插槽可以实现组件复用的同时显示不同的内容

具名插槽:slot开关可以写多个,并且可以精准定位到我们想要的位置

作用域插槽:子组件可以传递数据给父组件


54ce487d61ba46f2a6018ecae9b7da80.png

 

好了,兄弟姐妹们,本文结束喽!如果有未知的疑问,大家留言我会尽我所能帮助大家

下篇文章将讲解【路由】的使用,本专栏将持续更新,欢迎关注~ 

 


http://www.ppmy.cn/news/11345.html

相关文章

结构体内存对齐与结构体位段:学习笔记8

目录 一.结构体基础知识 1. 结构体的特殊声明 2. 结构的自引用 3.结构体变量的定义和初始化 二.结构体内存对齐 1.关键概念&#xff1a; 2.计算示例 3.嵌套结构体的内存计算 4.结构体内存对齐的意义 5.定义结构体时的注意事项 6.修改默认对齐数 附&#xff1a;关…

Linux进程状态与系统负载检测

1.基础知识-进程的5个状态进程可以分为五个状态&#xff0c;分别是&#xff1a;1&#xff09;创建状态一个应用程序从系统上启动&#xff0c;首先就是进入创建状态&#xff0c;需要获取系统资源创建进程管理块&#xff08;PCB&#xff09;完成资源分配。2) 就绪状态在创建状态完…

Java多线程案例——定时器

一&#xff0c;定时器1.定时器的概念定时器是Java开发中一个重要的组件&#xff08;功能类似于闹钟&#xff09;&#xff0c;可以指定一个任务在多长时间后执行&#xff08;尤其在网络编程的时候&#xff0c;如果网络卡顿很长时间没有响应用户的需求&#xff0c;此时可以使用定…

Codeforces Round #841 (Div. 2) (A--D)

[TOC](Codeforces Round #841 (Div. 2)(A–D)) A、 Joey Takes Money 1、题目 2、思路 3、代码 #include<iostream>#include<algorithm>#include<cstring>using namespace std;typedef unsigned long long ll;int main(){ll t;cin>>t;while(t--){int…

ArcGIS基础实验操作100例--实验84查找面到直线的最近点位置

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验84 查找面到直线的最近点位置 目录 一、实验背景 二、实验数据 三、实验步骤 &#…

springAOP的注解使用

注解使用导入依赖常用注解&#xff1a;注意&#xff0c;给测试类起名字的时候千万不要定义成Test&#xff0c;测试的方法不可以有参数&#xff0c;不可以有返回值在使用注解的时候&#xff0c;还需要告诉spring应该从哪个包开始扫描,一般在定义的时候都写上相同包的路径需要导入…

达摩院2023十大科技趋势发布,生成式AI将进入应用爆发期

1月11日&#xff0c;达摩院2023十大科技趋势发布&#xff0c;生成式AI、Chiplet模块化设计封装、全新云计算体系架构等技术入选。达摩院认为&#xff0c;全球科技日趋显现出交叉融合发展的新态势&#xff0c;尤其在信息与通信技术&#xff08;ICT&#xff09;领域酝酿的新裂变&…

RK3399平台开发系列讲解(内核调试篇)如何使用perf进行性能优化

🚀返回专栏总目录 文章目录 一、perf list命令二、perf record/report命令三、perf stat命令四、perf top命令五、火焰图沉淀、分享、成长,让自己和他人都能有所收获!😄 📢perf 可以在 CPU Usage 增高的节点上找到具体的引起 CPU 增高的函数,然后我们就可以有针对性地…