Vue2向Vue3过度核心技术插槽 Love The Way You Lie 2024-03-24 21:48 83阅读 0赞 #### 目录 #### * * 1 插槽-默认插槽 * * 1.作用 * 2.需求 * 3.问题 * 4.插槽的基本语法 * 5.代码示例 * 6.总结 * 2 插槽-后备内容(默认值) * * 1.问题 * 2.插槽的后备内容 * 3.语法 * 4.效果 * 5.代码示例 * 3 插槽-具名插槽 * * 1.需求 * 2.具名插槽语法 * 3.v-slot的简写 * 4.总结 * 4 作用域插槽 * * 1.插槽分类 * 2.作用 * 3.场景 * 4.使用步骤 * 5.代码示例 * 6.总结 * 5 综合案例 - 商品列表-MyTag组件抽离 * * 1.需求说明 * 2.代码准备 * 3.my-tag组件封装-创建组件 * 6 综合案例-MyTag组件控制显示隐藏 * 7 综合案例-MyTag组件进行v-model绑定 * 8 综合案例-封装MyTable组件-动态渲染数据 * 9 综合案例-封装MyTable组件-自定义结构 * 10 单页应用程序介绍 * * 1.概念 * 2.具体示例 * 3.单页应用 VS 多页面应用 -------------------- ### 1 插槽-默认插槽 ### ![在这里插入图片描述][b99d04a0f08b4a6d8e1286194a9f5a60.png] #### 1.作用 #### 让组件内部的一些 **结构** 支持 **自定义** ![在这里插入图片描述][cd526dbc2069474aa401918407494815.png] #### 2.需求 #### 将需要多次显示的对话框,封装成一个组件 #### 3.问题 #### 组件的内容部分,**不希望写死**,希望能使用的时候**自定义**。怎么办 #### 4.插槽的基本语法 #### 1. 组件内需要定制的结构部分,改用\*\*\*\*占位 2. 使用组件时, \*\*\*\*标签内部, 传入结构替换slot 3. 给插槽传入内容时,可以传入**纯文本、html标签、组件** ![在这里插入图片描述][b6778af2852e429ca4e65922a912c2d7.png] #### 5.代码示例 #### MyDialog.vue <template> <div class="dialog"> <div class="dialog-header"> <h3>友情提示</h3> <span class="close">✖️</span> </div> <div class="dialog-content"> 您确定要进行删除操作吗? </div> <div class="dialog-footer"> <button>取消</button> <button>确认</button> </div> </div> </template> <script> export default { data () { return { } } } </script> <style scoped> * { margin: 0; padding: 0; } .dialog { width: 470px; height: 230px; padding: 0 25px; background-color: #ffffff; margin: 40px auto; border-radius: 5px; } .dialog-header { height: 70px; line-height: 70px; font-size: 20px; border-bottom: 1px solid #ccc; position: relative; } .dialog-header .close { position: absolute; right: 0px; top: 0px; cursor: pointer; } .dialog-content { height: 80px; font-size: 18px; padding: 15px 0; } .dialog-footer { display: flex; justify-content: flex-end; } .dialog-footer button { width: 65px; height: 35px; background-color: #ffffff; border: 1px solid #e1e3e9; cursor: pointer; outline: none; margin-left: 10px; border-radius: 3px; } .dialog-footer button:last-child { background-color: #007acc; color: #fff; } </style> App.vue <template> <div> <MyDialog> </MyDialog> </div> </template> <script> import MyDialog from './components/MyDialog.vue' export default { data () { return { } }, components: { MyDialog } } </script> <style> body { background-color: #b3b3b3; } </style> #### 6.总结 #### 场景:组件内某一部分结构不确定,想要自定义怎么办 使用:插槽的步骤分为哪几步? ### 2 插槽-后备内容(默认值) ### #### 1.问题 #### 通过插槽完成了内容的定制,传什么显示什么, 但是如果不传,则是空白 ![在这里插入图片描述][726f80450e2e4b52ba8d7b9857f22739.png] 能否给插槽设置 默认显示内容 呢? #### 2.插槽的后备内容 #### 封装组件时,可以为预留的 `<slot>` 插槽提供后备内容(默认内容)。 #### 3.语法 #### 在 标签内,放置内容, 作为默认显示内容 ![在这里插入图片描述][dddd3f592c3847af8bc1929717e58178.png] #### 4.效果 #### * 外部使用组件时,不传东西,则slot会显示后备内容 ![在这里插入图片描述][7f4df03277ab4e899a7c3bce49069c19.png] * 外部使用组件时,传东西了,则slot整体会被换掉 ![在这里插入图片描述][b39f2de1119449c59d3722c6c07535cd.png] #### 5.代码示例 #### App.vue <template> <div> <MyDialog></MyDialog> <MyDialog> 你确认要退出么 </MyDialog> </div> </template> <script> import MyDialog from './components/MyDialog.vue' export default { data () { return { } }, components: { MyDialog } } </script> <style> body { background-color: #b3b3b3; } </style> ### 3 插槽-具名插槽 ### #### 1.需求 #### 一个组件内有多处结构,需要外部传入标签,进行定制 ![在这里插入图片描述][c702ff6da44e49db9a8639efaf664f2a.png] 上面的弹框中有**三处不同**,但是**默认插槽**只能**定制一个位置**,这时候怎么办呢? #### 2.具名插槽语法 #### * 多个slot使用name属性区分名字 ![在这里插入图片描述][24c5d3a5562f4720adb4a88a8ca158e9.png] * template配合v-slot:名字来分发对应标签 ![在这里插入图片描述][b6363c7b31ce4b1bac3e1d55d6cc453a.png] #### 3.v-slot的简写 #### v-slot写起来太长,vue给我们提供一个简单写法 **v-slot —> \#** #### 4.总结 #### * 组件内 有多处不确定的结构 怎么办? * 具名插槽的语法是什么? * v-slot:插槽名可以简化成什么? ### 4 作用域插槽 ### #### 1.插槽分类 #### * 默认插槽 * 具名插槽 插槽只有两种,作用域插槽不属于插槽的一种分类 #### 2.作用 #### 定义slot 插槽的同时, 是可以**传值**的。给 **插槽** 上可以 **绑定数据**,将来 **使用组件时可以用** #### 3.场景 #### 封装表格组件 ![在这里插入图片描述][7b80f1a13b4743f2b2b971197b318469.png] #### 4.使用步骤 #### 1. 给 slot 标签, 以 添加属性的方式传值 <slot :id="item.id" msg="测试文本"></slot> 2. 所有添加的属性, 都会被收集到一个对象中 { id: 3, msg: '测试文本' } 3. 在template中, 通过 `#插槽名= "obj"` 接收,默认插槽名为 default <MyTable :list="list"> <template #default="obj"> <button @click="del(obj.id)">删除</button> </template> </MyTable> #### 5.代码示例 #### MyTable.vue <template> <table class="my-table"> <thead> <tr> <th>序号</th> <th>姓名</th> <th>年纪</th> <th>操作</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>赵小云</td> <td>19</td> <td> <button> 查看 </button> </td> </tr> <tr> <td>1</td> <td>张小花</td> <td>19</td> <td> <button> 查看 </button> </td> </tr> <tr> <td>1</td> <td>孙大明</td> <td>19</td> <td> <button> 查看 </button> </td> </tr> </tbody> </table> </template> <script> export default { props: { data: Array } } </script> <style scoped> .my-table { width: 450px; text-align: center; border: 1px solid #ccc; font-size: 24px; margin: 30px auto; } .my-table thead { background-color: #1f74ff; color: #fff; } .my-table thead th { font-weight: normal; } .my-table thead tr { line-height: 40px; } .my-table th, .my-table td { border-bottom: 1px solid #ccc; border-right: 1px solid #ccc; } .my-table td:last-child { border-right: none; } .my-table tr:last-child td { border-bottom: none; } .my-table button { width: 65px; height: 35px; font-size: 18px; border: 1px solid #ccc; outline: none; border-radius: 3px; cursor: pointer; background-color: #ffffff; margin-left: 5px; } </style> App.vue <template> <div> <MyTable :data="list"></MyTable> <MyTable :data="list2"></MyTable> </div> </template> <script> import MyTable from './components/MyTable.vue' export default { data () { return { list: [ { id: 1, name: '张小花', age: 18 }, { id: 2, name: '孙大明', age: 19 }, { id: 3, name: '刘德忠', age: 17 }, ], list2: [ { id: 1, name: '赵小云', age: 18 }, { id: 2, name: '刘蓓蓓', age: 19 }, { id: 3, name: '姜肖泰', age: 17 }, ] } }, components: { MyTable } } </script> #### 6.总结 #### 1.作用域插槽的作用是什么? 2.作用域插槽的使用步骤是什么? ### 5 综合案例 - 商品列表-MyTag组件抽离 ### ![在这里插入图片描述][46807aa6e40042f480b0219b426f7f83.png] #### 1.需求说明 #### 1. **my-tag 标签组件封装** (1) 双击显示输入框,输入框获取焦点 (2) 失去焦点,隐藏输入框 (3) 回显标签信息 (4) 内容修改,回车 → 修改标签信息 1. **my-table 表格组件封装** (1) 动态传递表格数据渲染 (2) 表头支持用户自定义 (3) 主体支持用户自定义 #### 2.代码准备 #### <template> <div class="table-case"> <table class="my-table"> <thead> <tr> <th>编号</th> <th>名称</th> <th>图片</th> <th width="100px">标签</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>梨皮朱泥三绝清代小品壶经典款紫砂壶</td> <td> <img src="https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg" /> </td> <td> <div class="my-tag"> <!-- <input class="input" type="text" placeholder="输入标签" /> --> <div class="text"> 茶具 </div> </div> </td> </tr> <tr> <td>1</td> <td>梨皮朱泥三绝清代小品壶经典款紫砂壶</td> <td> <img src="https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg" /> </td> <td> <div class="my-tag"> <!-- <input ref="inp" class="input" type="text" placeholder="输入标签" /> --> <div class="text"> 男靴 </div> </div> </td> </tr> </tbody> </table> </div> </template> <script> export default { name: 'TableCase', components: {}, data() { return { goods: [ { id: 101, picture: 'https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg', name: '梨皮朱泥三绝清代小品壶经典款紫砂壶', tag: '茶具', }, { id: 102, picture: 'https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg', name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌', tag: '男鞋', }, { id: 103, picture: 'https://yanxuan-item.nosdn.127.net/cd4b840751ef4f7505c85004f0bebcb5.png', name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm', tag: '儿童服饰', }, { id: 104, picture: 'https://yanxuan-item.nosdn.127.net/56eb25a38d7a630e76a608a9360eec6b.jpg', name: '基础百搭,儿童套头针织毛衣1-9岁', tag: '儿童服饰', }, ], } }, } </script> <style lang="less" scoped> .table-case { width: 1000px; margin: 50px auto; img { width: 100px; height: 100px; object-fit: contain; vertical-align: middle; } .my-table { width: 100%; border-spacing: 0; img { width: 100px; height: 100px; object-fit: contain; vertical-align: middle; } th { background: #f5f5f5; border-bottom: 2px solid #069; } td { border-bottom: 1px dashed #ccc; } td, th { text-align: center; padding: 10px; transition: all 0.5s; &.red { color: red; } } .none { height: 100px; line-height: 100px; color: #999; } } .my-tag { cursor: pointer; .input { appearance: none; outline: none; border: 1px solid #ccc; width: 100px; height: 40px; box-sizing: border-box; padding: 10px; color: #666; &::placeholder { color: #666; } } } } </style> #### 3.my-tag组件封装-创建组件 #### MyTag.vue <template> <div class="my-tag"> <!-- <input class="input" type="text" placeholder="输入标签" /> --> <div class="text"> 茶具 </div> </div> </template> <script> export default { } </script> <style lang="less" scoped> .my-tag { cursor: pointer; .input { appearance: none; outline: none; border: 1px solid #ccc; width: 100px; height: 40px; box-sizing: border-box; padding: 10px; color: #666; &::placeholder { color: #666; } } } </style> App.vue <template> ... <tbody> <tr> .... <td> <MyTag></MyTag> </td> </tr> </tbody> ... </template> <script> import MyTag from './components/MyTag.vue' export default { name: 'TableCase', components: { MyTag, }, .... </script> ### 6 综合案例-MyTag组件控制显示隐藏 ### MyTag.vue <template> <div class="my-tag"> <input v-if="isEdit" v-focus ref="inp" class="input" type="text" placeholder="输入标签" @blur="isEdit = false" /> <div v-else @dblclick="handleClick" class="text"> 茶具 </div> </div> </template> <script> export default { data () { return { isEdit: false } }, methods: { handleClick () { this.isEdit = true } } } </script> main.js // 封装全局指令 focus Vue.directive('focus', { // 指令所在的dom元素,被插入到页面中时触发 inserted (el) { el.focus() } }) ### 7 综合案例-MyTag组件进行v-model绑定 ### App.vue <MyTag v-model="tempText"></MyTag> <script> export default { data(){ tempText:'水杯' } } </script> MyTag.vue <template> <div class="my-tag"> <input v-if="isEdit" v-focus ref="inp" class="input" type="text" placeholder="输入标签" :value="value" @blur="isEdit = false" @keyup.enter="handleEnter" /> <div v-else @dblclick="handleClick" class="text"> { { value }} </div> </div> </template> <script> export default { props: { value: String }, data () { return { isEdit: false } }, methods: { handleClick () { this.isEdit = true }, handleEnter (e) { // 非空处理 if (e.target.value.trim() === '') return alert('标签内容不能为空') this.$emit('input', e.target.value) // 提交完成,关闭输入状态 this.isEdit = false } } } </script> ### 8 综合案例-封装MyTable组件-动态渲染数据 ### App.vue <template> <div class="table-case"> <MyTable :data="goods"></MyTable> </div> </template> <script> import MyTable from './components/MyTable.vue' export default { name: 'TableCase', components: { MyTable }, data(){ return { .... } }, } </script> MyTable.vue <template> <table class="my-table"> <thead> <tr> <th>编号</th> <th>名称</th> <th>图片</th> <th width="100px">标签</th> </tr> </thead> <tbody> <tr v-for="(item, index) in data" :key="item.id"> <td>{ { index + 1 }}</td> <td>{ { item.name }}</td> <td> <img :src="item.picture" /> </td> <td> 标签内容 <!-- <MyTag v-model="item.tag"></MyTag> --> </td> </tr> </tbody> </table> </template> <script> export default { props: { data: { type: Array, required: true } } }; </script> <style lang="less" scoped> .my-table { width: 100%; border-spacing: 0; img { width: 100px; height: 100px; object-fit: contain; vertical-align: middle; } th { background: #f5f5f5; border-bottom: 2px solid #069; } td { border-bottom: 1px dashed #ccc; } td, th { text-align: center; padding: 10px; transition: all .5s; &.red { color: red; } } .none { height: 100px; line-height: 100px; color: #999; } } </style> ### 9 综合案例-封装MyTable组件-自定义结构 ### App.vue <template> <div class="table-case"> <MyTable :data="goods"> <template #head> <th>编号</th> <th>名称</th> <th>图片</th> <th width="100px">标签</th> </template> <template #body="{ item, index }"> <td>{ { index + 1 }}</td> <td>{ { item.name }}</td> <td> <img :src="item.picture" /> </td> <td> <MyTag v-model="item.tag"></MyTag> </td> </template> </MyTable> </div> </template> <script> import MyTag from './components/MyTag.vue' import MyTable from './components/MyTable.vue' export default { name: 'TableCase', components: { MyTag, MyTable }, data () { return { .... } } </script> MyTable.vue <template> <table class="my-table"> <thead> <tr> <slot name="head"></slot> </tr> </thead> <tbody> <tr v-for="(item, index) in data" :key="item.id"> <slot name="body" :item="item" :index="index" ></slot> </tr> </tbody> </table> </template> <script> export default { props: { data: { type: Array, required: true } } }; </script> ### 10 单页应用程序介绍 ### #### 1.概念 #### 单页应用程序:SPA【Single Page Application】是指所有的功能都在**一个html页面**上实现 #### 2.具体示例 #### 单页应用网站: 网易云音乐 [https://music.163.com/][https_music.163.com] 多页应用网站:京东 https://jd.com/ #### 3.单页应用 VS 多页面应用 #### ![在这里插入图片描述][5bff9109aa654f2aa0cc2fa8c1fe64b6.png] 单页应用类网站:系统类网站 / 内部网站 / 文档类网站 / 移动端站点 多页应用类网站:公司官网 / 电商类网站 [b99d04a0f08b4a6d8e1286194a9f5a60.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/d57be80f67d54f8c85c00c4581e05928.png [cd526dbc2069474aa401918407494815.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/1d396dafa5f749858c3233a2ce020c41.png [b6778af2852e429ca4e65922a912c2d7.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/f7e283a51d5247e6940a2608a9c1ac6a.png [726f80450e2e4b52ba8d7b9857f22739.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/ea6adc22da6742249e59f128c219b169.png [dddd3f592c3847af8bc1929717e58178.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/8c233c82c6c74c2a80ac3a114ba205c1.png [7f4df03277ab4e899a7c3bce49069c19.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/5d3659fe4e4b48f3afbc739699e16d54.png [b39f2de1119449c59d3722c6c07535cd.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/e5473718ec6c408982f1df70dc15c740.png [c702ff6da44e49db9a8639efaf664f2a.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/57d1a4f91c524664bd1046987d5dc49a.png [24c5d3a5562f4720adb4a88a8ca158e9.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/c7679fcc4edc49bd8f982cef38b962b4.png [b6363c7b31ce4b1bac3e1d55d6cc453a.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/4f2edabf6ebb46d09b91eba96dbb0b4e.png [7b80f1a13b4743f2b2b971197b318469.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/6968886d9db74e3ea68f07f563027c81.png [46807aa6e40042f480b0219b426f7f83.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/2c801c2c917547fe90dc0642b5ea750a.png [https_music.163.com]: https://music.163.com/ [5bff9109aa654f2aa0cc2fa8c1fe64b6.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/13/068bbb9c07ba41c0a150c4e54fe61caa.png
相关 Vue2向Vue3过度核心技术综合案例 目录 1 面经基础版-案例效果分析 1.面经效果演示 2.功能分析 3.实现思路分析:配置路由 曾经终败给现在/ 2024年03月24日 21:50/ 0 赞/ 94 阅读
相关 Vue2向Vue3过度核心技术声明式导航 目录 1 声明式导航-导航链接 1.需求 2.解决方案 3.通过router-link自带的两 本是古典 何须时尚/ 2024年03月24日 21:49/ 0 赞/ 83 阅读
相关 Vue2向Vue3过度核心技术插槽 目录 1 插槽-默认插槽 1.作用 2.需求 3.问题 4.插槽的基本语 Love The Way You Lie/ 2024年03月24日 21:48/ 0 赞/ 84 阅读
相关 Vue2向Vue3过度核心技术组件通信 目录 1 组件基础知识scoped解决样式冲突 1.1 默认情况: 1.2 代码演示 1.3 浅浅的花香味﹌/ 2024年03月24日 21:37/ 0 赞/ 89 阅读
相关 Vue2向Vue3过度核心技术生命周期 目录 1 Vue生命周期 2 Vue生命周期钩子 3 生命周期钩子小案例 1.1 在created中发送数据 小灰灰/ 2024年03月24日 21:35/ 0 赞/ 82 阅读
相关 Vue2向Vue3过度核心技术watch侦听器 目录 1 watch侦听器 1.1 作用: 1.2 语法: 1.3 侦听器代码准备 以你之姓@/ 2024年03月24日 21:33/ 0 赞/ 58 阅读
还没有评论,来说两句吧...