一、定义一个vue分页组件,实现客户端分页功能
1.1、子组件A(页数按钮)
<!-- 本组件用于遍历分页的页数按钮 --> <template lang=""> <div class="btn-box"> <!-- 页数,下标+1 --> {{pzie + 1}} </div> </template> <script lang="ts"> import { ref } from 'vue' export default { // 接收参数 "size" props: ['size'], setup (p:any) { // 响应式参数 const pzie = ref(p.size) // 暴露出去页面上 return { pzie } } } </script> <style > .btn-box{ width: 30px; height: 30px; line-height: 30px; border-radius: 2.5px; background-color: #ddd; } </style>
1.1、父组件
<!-- 本组件用于实现分页的功能 --> <template lang=""> <div> <!-- 表格里面的数据 --> <table border="1" width="60%"> <tr> <th>商品编号</th> <th>商品名称</th> <th>商品价格</th> </tr> <!-- 遍历数据到表格上 --> <tr v-for="item in data" :key="item.id"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.price}}</td> </tr> </table> <div class="btn2-box"> <button @click = btnsx(0)>上一页</button> <!-- 显示页数的按钮 --> <!-- 功能:添加类、:size="i":(传下标到子组件里显示页数) --> <Btn class="Btn-st" v-for="(item, i) in list.btncount" :class="{'addclass': list.addclass==i}" :key="i" :size="i" @click="clicknext(i)"></Btn> <button @click = btnsx(1)>下一页</button> <div class="skip"> 跳转到:<input type="text" v-model="nums"> 页 <button @click="skip()">Go</button> </div> </div> </div> </template> <script lang="ts"> // 导入子组件文件 import Btn from "../components/1.1 分页按钮.vue"; import { reactive, ref, toRefs } from 'vue' export default { // 注册子组件 components: { Btn }, setup() { // 参数1:模拟数据库里的数据 // 参数2:在页面上显示的数据 // 参数3:显示在分页上的总条数、当前页、每页显示的数量、总页数 const s: any = reactive({ sql: [], data: [], list: {} }); // 绑定跳转页面的文本框数据 let nums:any = ref(1); // 循环100条数据 for (let i = 0; i < 100; i++) { // 把100条数据存储到sql数组里面 s.sql.push({ id: i + 1, // 编号,从1开始 name: `桃子${i + 1}`, // 名称后面+1 price: `${(i + 100) * 2}` // 价格 }) } // 添加属性到参数3里面 s.list.toal = s.sql.length // 总数据长度 s.list.danqianye = 1 // 当前页 默认为 1 s.list.pagezie = 10 // 每一页显示数量 s.list.btncount = s.list.toal / s.list.pagezie // 总页数 = 总数据长度 / 每一页显示数据数量 s.list.addclass = 0; // 这个变量用于给显示页数的按钮(有颜色)添加类 // 参数1 等于数据源(sql)起点下标 例如0 就等于从 s.sql[0] 开始拿数据 // 参数2 等于数据源(sql)终点下标 例如10 就等于从 s.sql[9] 结束 function createfenye(ii: any, i2: any) { // 每次进来都要清空之前所缓存的数据,要不然就实现不了下一页的效果 s.data = [] // 每一页的数据从参数1开始,到参数2结束 for (let i = ii; i < i2; i++) { // 然后重新赋值给s.data数组 s.data.push(s.sql[i]) } } // 初始化的时候就从0条数据开始到10条数据结束获取数据 createfenye(0, 10) // 该方法用于实现点击页数按钮功能,传入该页数按钮中的下标 function clicknext(i: any) { // 当前页赋值为i,跟着下标的变化而变化当前页的值 s.list.danqianye = i // 显示页数按钮(有颜色)的值也需要变化 s.list.addclass = i // 例如 i 的下标等于 0 的时候 i+1,就代表它在第一页 // 1 × 10 等于10, 10 - 10 = 0 说明它是从0 开始 赋值数据到 s.data 里边 // i 的下标等于 0 终点就等于 i + 1 = 1, 1 x 10 = 10, 说明它是从10 结束 赋值 createfenye(((i + 1) * 10 - 10), ((i + 1) * 10)) } // 该方法用于实现点击上一页与下一页功能,传入1(下一页)或0(上一页)判断用户点击的是哪个按钮 function btnsx(i: any) { if (i == 0) { // i为0,即点击了上一页 // 获取到上一页的数据 createfenye(((s.list.danqianye - 1) * 10 - 10), ((s.list.danqianye - 1) * 10)) // 然后当前页也需要-1 s.list.danqianye-- // 显示页数按钮(有颜色)也需要后退一个 s.list.addclass-- } else { // 与上面相反 createfenye(((s.list.danqianye + 1) * 10 - 10), ((s.list.danqianye + 1) * 10)) s.list.danqianye++ s.list.addclass++ } } // 该方法用于跳转页面的 function skip(){ // 当前页赋值为i,跟着下标的变化而变化当前页的值 s.list.danqianye = nums.value // 显示页数按钮(有颜色)的值也需要变化 s.list.addclass = nums.value console.log(s.list.danqianye); console.log(s.list.addclass); createfenye(((s.list.danqianye) * 10 - 10), ((s.list.danqianye) * 10)) s.list.addclass-- } // 暴露到页面上 return { ...toRefs(s), clicknext, btnsx, nums, skip } } } </script> <style > table { margin: auto; height: 350px; border-collapse: collapse; } th { background-color: pink; color: #fff; } .btn2-box { display: flex; width: 60%; margin: auto; margin-top: 30px; } .Btn-st { margin: 5px; cursor: pointer; } .addclass { background-color: pink; color: #fff; } .skip { width: 240px; height: 30px; /* border: 1px solid red; */ margin-left: 30px; margin-top: 5px; } .skip input{ width: 70px; height: 20px; text-align: center; outline: none; } .skip button{ height: 26px; margin-left: 10px; } </style>
1.3、运行结果
二、使用vue3实现图书列表与详细展示功能
2.1、子组件A(可能想搜的)
<!-- 本组件为图书列表中的“ 可能想搜索的图书 ” 部分 --> <template lang=""> <!-- 把从父组件传过来的数据通过遍历循环出来 --> <div class="hot-min" v-for="(item,i) in list.hot">{{item}}</div> </template> <script lang="ts"> import { reactive, ref, toRefs } from 'vue'; export default { // 接收参数 props: ['data'], setup(p:any) { // 定义一个变量把数据存储起来 const s:any = reactive({list:[] }); s.list.hot= p.data // 暴露出去页面上 return { ...toRefs(s) } } } </script> <style> .hot-min { width: 80px; height: 40px; background-color: #fff; margin: 10px; line-height: 40px; } </style>
2.2、子组件B(图书列表)
<!-- 本组件用于显示所有的图书列表 --> <template lang=""> <div class="main" v-for="(item,i) in list.hot" @click="clicklist(item)"> <div class="main_left"> <img :src="item.tp" alt="" > </div> <div class="main_right" > <p style="font-size: 18px;">{{item.name}}</p> <p style="color: #aaa;font-size: 14px;">{{item.zz}}</p> <p style="color: red;font-size: 16px;">¥ {{item.price}}</p> </div> </div> </template> <script lang="ts"> // 导入路由文件 import { useRouter } from 'vue-router' import { reactive, toRefs } from 'vue'; export default { setup() { const s: any = reactive({ list: [], list2: [] }); s.list.hot = [ { name: "web 前端开发", zz: "南方IT学院", price: "62.4", tp: "https://ts1.cn.mm.bing.net/th/id/R-C.5c5ec1769389901eac83e9cf75a5bd33?rik=GXnLovzVPOcEUg&riu=http%3a%2f%2fwww.tup.tsinghua.edu.cn%2fupload%2fbigbookimg3%2f080900-01.jpg&ehk=4efizNnDT%2fRsmCZVq5H2UkONQ%2bBT2oOu6%2br%2bP511Lv0%3d&risl=&pid=ImgRaw&r=0" }, { name: "JavaScript语言精粹", zz: "清华大学出版社", price: "88.9", tp: "https://pic2.zhimg.com/v2-a4265bf1750016b9a83abdc60a8471c7_b.jpg" }, { name: "HTML5权威指南", zz: "北京大学出版社", price: "108.0", tp: "https://codesheep.oss-cn-hangzhou.aliyuncs.com/blog/20200916233828.png" }, { name: "ES6标准入门", zz: "清华大学出版社", price: "35.8", tp: "https://pic2.zhimg.com/v2-17c68027e62866178d5159374318ad7d_b.jpg" }, { name: "图解css3", zz: "南方it学院", price: "11.2", tp: "https://pic2.zhimg.com/v2-64c56a356fa4777037ffd15233417585_b.jpg" }, { name: "node.js", zz: "人民大学出版社", price: "77.9", tp: "https://ts1.cn.mm.bing.net/th/id/R-C.a6bfd782f3aa77ca473a208514a65e18?rik=r07N6f2SwTOl1w&riu=http%3a%2f%2fwww.fairysoftware.com%2fad_images%2fqian_duan_kai_fa_06.jpg&ehk=6nr%2fdlTyGl4EtlcAJu3KDeRyRLAH9VvZC8Ae58EB1y0%3d&risl=&pid=ImgRaw&r=0" }, ] // 路由跳转 const $router = useRouter(); // 该方法实现点击每一个图书时,跳转到该图书的详情页上,通过query传递点击的图书信息参数过去 function clicklist(item:any) { // path是路由路径 $router.push({ path:'info', query:item }) console.log(item); } // 暴露出去页面上 return { ...toRefs(s),clicklist } } } </script> <style> /* 身体 */ .main { width: 90%; height: 100px; margin: auto; /* border: 1px solid magenta; */ margin-top: 20px; display: flex; } .main_left { width: 35%; height: 100%; } .main_left img { width: 100%; height: 100%; object-fit: contain; } .main_right { width: 65%; height: 100%; padding-bottom: 10px; border-bottom: 1px solid #aaa; } .main_right p { text-align: left; line-height: 20px; margin: 10px; } </style>
2.3、子组件C(图书详情页)
<!-- 本组件用于展示某一本图书信息的详情页 --> <template lang=""> <div class="headinfo"> <svg t="1667807456323" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2517" width="25" height="32"><path d="M677.391515 873.916768c-7.86101 0-15.618586-2.999596-21.617778-8.895354L324.473535 533.721212c-11.998384-11.894949-11.998384-31.340606 0-43.235555L655.670303 159.288889c5.999192-5.999192 13.756768-8.895354 21.617778-8.895354 7.757576 0 15.618586 2.999596 21.617778 8.895354 11.894949 11.894949 11.894949 31.237172 0 43.235555L389.223434 512.103434 698.905859 821.785859c11.894949 11.998384 11.894949 31.340606 0 43.235555-5.895758 5.895758-13.756768 8.895354-21.514344 8.895354z m0 0" p-id="2518" fill="#707070"></path></svg> <span style="color:red;border-bottom: 2px solid #fb8768;">商品</span> <span>详情</span> <span>评论</span> <span>推荐</span> <svg t="1667807536833" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3774" width="25" height="32"><path d="M746.662019 512c0 51.835575 42.044582 93.865831 93.865831 93.865831 51.851948 0 93.865831-42.029232 93.865831-93.865831 0-51.836599-42.013883-93.865831-93.865831-93.865831C788.706601 418.135192 746.662019 460.163401 746.662019 512z" p-id="3775" fill="#515151"></path><path d="M89.604272 512c0 51.835575 42.043558 93.865831 93.864808 93.865831 51.822272 0 93.865831-42.029232 93.865831-93.865831 0-51.836599-42.043558-93.865831-93.865831-93.865831C131.648854 418.135192 89.604272 460.163401 89.604272 512z" p-id="3776" fill="#515151"></path><path d="M418.132634 512c0 51.835575 42.013883 93.865831 93.866854 93.865831 51.821249 0 93.864808-42.029232 93.864808-93.865831 0-51.836599-42.043558-93.865831-93.864808-93.865831C460.146517 418.135192 418.132634 460.163401 418.132634 512z" p-id="3777" fill="#515151"></path></svg> </div> <div class="picture"> <!-- 用传过来的参数,直接渲染到页面 --> <img :src="route.query.tp" alt=""> </div> <div class="text"> <!-- 这部分也是获取路由跳转时传过来的信息,直接渲染到页面上 --> <p>{{route.query.name}}</p> <P style="color:#aaa;font-size: 16px;">{{route.query.zz}}</P> <P style="color:red;font-size: 16px;">¥ <span style="font-size: 20px;">{{route.query.price}}</span> </P> </div> <div class="bottom"> <div> <svg t="1667808724702" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2531" width="32" height="32"><path d="M940.960749 425.143816c0.093121-17.86488-2.838651-35.791158-8.207939-52.113915-0.061398-0.463558-0.153496-0.89437-0.246617-1.26583-0.370437-1.788739-0.86367-3.517103-1.573845-5.183046L858.609159 186.54565c-12.527314-37.334303-48.50369-60.228733-90.589205-60.32083L260.369006 126.22482c-42.641169 0-75.778894 22.678512-87.781252 58.531068L94.833879 368.463909c-0.370437 1.079588-0.771573 2.684132-1.110287 4.319375-5.646604 17.339924-8.485255 35.143405-8.485255 53.008284 0.047072 47.364751 19.658735 91.617627 53.040007 123.1856l0.214894 269.90315c0 43.50484 35.452443 78.895885 79.049381 78.895885l580.622914-0.370437c43.535539-0.093121 78.957283-35.57524 78.957283-79.111802l-0.058328-260.299421C917.076782 526.08888 940.986331 477.395878 940.960749 425.143816zM798.072411 835.695287l-580.529793 0.370437c-9.564843 0-17.339924-7.713682-17.339924-17.217127l-0.185218-232.914724c16.764825 5.293563 35.163871 7.983835 55.045687 7.983835 50.632167-0.153496 97.531314-22.400173 129.496329-60.47535 31.81152 37.766139 78.340229 59.858296 128.880299 60.166311 50.138934-0.401136 96.543823-22.586414 128.200824-60.32083 31.965016 38.075177 78.926584 60.228733 129.805368 60.228733 15.559371-0.077771 30.233582-1.77646 43.916209-5.060249l0.051165 229.867318C815.413358 827.889507 807.606555 835.664587 798.072411 835.695287zM823.065641 520.114818c-13.977339 7.652284-31.410384 11.570523-51.68208 11.69332-37.58092 0-71.828932-19.068288-91.823312-51.434439-1.419326-3.055592-3.795443-8.114818-8.238638-12.989849-5.090948-5.708002-14.346753-12.464893-29.588899-12.464893-12.279674 0-23.418362 5.028527-29.712719 12.743232-4.16588 4.689812-6.448876 9.348925-8.084119 12.742209-19.74674 31.966039-53.718459 51.218522-90.527806 51.496861-37.272905-0.215918-71.335698-19.407002-91.206258-51.619658-1.388627-2.838651-3.703345-7.621585-7.312546-11.663644-14.502295-17.309224-46.960545-16.414855-59.610656-1.326205-4.659113 5.090948-7.096628 10.212596-8.670473 13.700023-19.931958 31.965016-54.211692 51.126424-91.607394 51.249221-19.931958 0-36.994566-3.734044-50.755987-11.07729l-0.030699 0c0 0 0 0-0.030699 0-35.297924-18.789948-57.235562-55.32198-57.266261-95.309716 0-11.81714 1.974981-23.727401 5.92392-35.328623 0.277316-0.832971 0.523933-1.759063 0.740874-2.715855l76.581166-181.054589c1.573845-4.628414 6.325056-18.72855 30.144554-18.72855l507.805468 0c9.780761 0.586354 26.628474 2.313695 32.613792 19.931958l71.706135 178.555675c0.278339 1.295506 0.617054 2.529613 0.926092 3.547803 3.980661 11.631922 5.954619 23.449062 5.954619 35.175127C879.375112 464.761116 857.80791 501.107929 823.065641 520.114818z" p-id="2532" fill="#707070"></path></svg> <p>店铺</p> </div> <div> <svg t="1667809633396" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4325" width="32" height="32"><path d="M510.7 894.6c-37.2 0-74.3-14.4-102.6-43.2l-0.2-0.2-269.6-277.9c-24.9-25.5-44-55.5-56.8-88.9-12.3-32.3-18.2-66.3-17.4-101.1 0.8-34.9 8.2-68.8 22.1-100.6 14.4-33 35.1-62.3 61.5-87 48.6-45.9 112.5-69.3 180-66.1 66.2 3.2 128.6 31.5 175.7 79.9l9 9.2 8.3-9.3c97.9-100.4 254-106.6 355.3-14.1l0.3 0.3c26.4 24.7 47.2 54 61.6 87.1 13.9 31.8 21.3 65.7 22.1 100.7 0.8 34.8-5.1 68.8-17.4 101.1-12.8 33.4-31.9 63.4-56.8 88.9l-272.4 278c-28.3 28.7-65.5 43.2-102.7 43.2zM458 800.5c29.1 29.6 76.4 29.5 105.5-0.1l272.3-277.9c35.7-36.6 54.8-85.5 53.7-137.5-1.2-52.3-22.7-100.7-60.6-136.2-73.1-66.6-186-61.8-257.5 10.9l-30.5 34.2-0.9 0.8c-15.2 14.8-38.7 14.6-53.5-0.5l-0.1-0.1-33-33.8c-34.7-35.6-80.5-56.4-129-58.8-48.4-2.3-94.2 14.4-128.8 47.1l-0.1 0.1c-38 35.5-59.6 83.9-60.8 136.2-1.2 52 17.9 100.9 53.7 137.7L458 800.5z" p-id="4326" fill="#707070"></path><path d="M339.7 288c-64.1 1.4-98.6 29.4-116.3 52.6-10.2 13.5-16 26.8-19.3 37-4.1 10.5-7.4 22.3-9.8 35.7-3.5 19.6 9.5 38.3 29 41.8 2.2 0.4 4.3 0.6 6.4 0.6 17.1 0 32.2-12.2 35.4-29.6 1.5-8.4 3.6-16 6.2-22.7l0.9-2.1c1.1-4 3.9-11.7 10.2-19.1 8.4-9.9 20.7-16.6 36.6-19.8 6.8-1.4 14.2-2.2 22.3-2.4 17.7-0.4 32.1-13.4 34.8-30.3 0.3-2.1 0.5-4.2 0.4-6.4-0.4-19.9-16.9-35.7-36.8-35.3z" p-id="4327" fill="#707070"></path></svg> <p>收藏</p> </div> <div> <svg t="1667810312978" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5320" width="32" height="32"><path d="M928.922574 99.438757l-67.214844 0c-15.159258 0-28.122501 10.878768-30.755468 25.803689l-15.35164 86.96977L222.034932 212.212216c-17.253966 0-31.233352 13.979386-31.233352 31.233352s13.979386 31.233352 31.233352 31.233352l582.540589 0-49.773613 281.97407c-8.103562 37.283138-29.688159 81.4388-86.410022 81.4388l-375.389646 0c-32.819476 0-57.504692-5.947456-76.324316-82.851986-0.11154-0.477884-0.243547-0.945535-0.376577-1.413186l-90.304725-306.293965c-4.89038-16.531512-22.23542-25.986861-38.797631-21.12718-16.541745 4.880147-25.997094 22.245653-21.12718 38.797631l90.101087 305.603233c15.830547 64.286142 44.582381 129.752156 136.829342 129.752156l375.389646 0c74.79959 0 129.97626-49.107441 147.605779-131.348514 0.081864-0.376577 0.152473-0.741897 0.213871-1.118474l71.697949-406.186046 41.014112 0c17.253966 0 31.233352-13.979386 31.233352-31.233352S946.17654 99.438757 928.922574 99.438757z" p-id="5321" fill="#707070"></path><path d="M361.610828 333.028862c-17.253966 0-31.233352 13.979386-31.233352 31.233352l0 30.470989c0 17.253966 13.979386 31.233352 31.233352 31.233352 17.253966 0 31.233352-13.979386 31.233352-31.233352l0-30.470989C392.84418 347.008248 378.86377 333.028862 361.610828 333.028862z" p-id="5322" fill="#707070"></path><path d="M605.376691 333.028862c-17.253966 0-31.233352 13.979386-31.233352 31.233352l0 30.470989c0 17.253966 13.979386 31.233352 31.233352 31.233352 17.253966 0 31.233352-13.979386 31.233352-31.233352l0-30.470989C636.610042 347.008248 622.630656 333.028862 605.376691 333.028862z" p-id="5323" fill="#707070"></path><path d="M560.28982 474.086505c-14.539134-9.292644-33.845853-5.083785-43.149752 9.455349-0.121773 0.193405-13.379729 19.449981-33.968649 19.449981-20.008706 0-32.453133-18.127869-33.287127-19.378349-9.17087-14.407128-28.274974-18.809391-42.824341-9.750061-14.650675 9.099239-19.155269 28.355815-10.044774 43.00649 11.214413 18.047028 41.980113 48.588625 86.156242 48.588625 43.952025 0 75.094302-30.308283 86.572728-48.222281C579.048045 502.717589 574.818721 483.389382 560.28982 474.086505z" p-id="5324" fill="#707070"></path><path d="M296.093649 739.519854c-51.668777 0-93.700055 42.031279-93.700055 93.700055 0 51.668777 42.031279 93.700055 93.700055 93.700055 51.668777 0 93.700055-42.031279 93.700055-93.700055C389.793704 781.550109 347.762425 739.519854 296.093649 739.519854zM296.093649 864.453261c-17.223267 0-31.233352-14.010085-31.233352-31.233352 0-17.223267 14.010085-31.233352 31.233352-31.233352s31.233352 14.010085 31.233352 31.233352C327.327 850.443176 313.316915 864.453261 296.093649 864.453261z" p-id="5325" fill="#707070"></path><path d="M670.89387 739.519854c-51.668777 0-93.700055 42.031279-93.700055 93.700055 0 51.668777 42.031279 93.700055 93.700055 93.700055 51.668777 0 93.700055-42.031279 93.700055-93.700055C764.593925 781.550109 722.56367 739.519854 670.89387 739.519854zM670.89387 864.453261c-17.223267 0-31.233352-14.010085-31.233352-31.233352 0-17.223267 14.010085-31.233352 31.233352-31.233352s31.233352 14.010085 31.233352 31.233352C702.127222 850.443176 688.117137 864.453261 670.89387 864.453261z" p-id="5326" fill="#707070"></path></svg> <p>购物车</p> </div> <div style="height: 60px;"> <button class="btn" >立即购买</button> <button class="btn" style="background-color:#f2564a">加入购物车</button> </div> </div> </template> <script lang="ts"> // 需要导入这个路由 import { useRoute } from 'vue-router'; export default { setup() { // 接收路由跳转时传过来的数据 const route = useRoute() // 通过route.query,打印传递过来的数据 console.log(route.query); return { route } } } </script> <style scoped> .headinfo { width: 100%; height: 33px; /* border: 1px solid magenta; */ display: flex; justify-content: space-between; } .headinfo span { line-height: 35px; } .picture { height: 200px; border-bottom: 1px solid #ddd; margin-top: 20px; padding-bottom: 10px; } .picture img { width: 100%; height: 100%; object-fit: contain; } .text { border-bottom: 1px solid #ddd; } .text p { text-align: left; margin-left: 20px; font-size: 18px; } .bottom { width: 100%; height: 60px; position: fixed; bottom: 0px; /* border: 1px solid red; */ display: flex; justify-content: space-around; } .bottom svg{ margin-top: 5px; } .bottom p { margin-top: -3px; font-size: 14px; } .btn { background-color: #febd21; width: 100px; height: 100%; border: none; color: #fff; font-size: 16px; } </style>
2.4、父组件
<!-- 本组件为父组件,用于展示图书列表的信息 --> <template lang=""> <div class="head"> <svg style="margin-top: 3px;" t="1667737776727" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2516" width="32" height="32"><path d="M710.4 838.4 358.4 492.8c-12.8-12.8-32-12.8-44.8 0l0 0c-12.8 12.8-12.8 32 0 44.8l352 352c12.8 12.8 32 12.8 44.8 0l0 0C723.2 876.8 723.2 851.2 710.4 838.4z" p-id="2517" fill="#707070"></path><path d="M358.4 531.2l352-352c12.8-12.8 12.8-32 0-44.8l0 0c-12.8-12.8-32-12.8-44.8 0L313.6 486.4c-12.8 12.8-12.8 32 0 44.8l0 0C326.4 544 345.6 544 358.4 531.2z" p-id="2518" fill="#707070"></path></svg> <div class="textbox"> <svg t="1667752526391" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2608" width="32" height="32"><path d="M663.006587 602.400314l-32.11848 0-12.063745-12.080118c40.177008-44.250786 64.278915-104.586905 64.278915-168.934382 0-144.831451-116.607671-261.4381-261.439123-261.4381-144.787449 0-261.386934 116.606648-261.386934 261.4381 0 144.831451 116.598462 261.387958 261.386934 261.387958 64.390455 0 124.725551-24.09372 168.993733-64.279938l12.011556 12.081141 0 32.162482 201.112213 201.051838 60.32691-60.335096L663.006587 602.400314zM421.664154 602.400314c-100.589875 0-181.021662-80.43281-181.021662-181.014499 0-100.641041 80.43281-181.014499 181.021662-181.014499 100.624668 0 181.005289 80.373458 181.005289 181.014499C602.669443 521.967504 522.288822 602.400314 421.664154 602.400314" p-id="2609" fill="#515151"></path></svg> <input type="text" /> </div> <span class="screen">筛选</span> </div> <div class="Deputy_head"> <span style="color:red">默认</span> <span >销量</span> <span >价格</span> <span >好评</span> <span >出版价格</span> </div> <div class="hot_search"> <!-- 导入子组件 --> <Search :data="lists"></Search> </div> <!-- 身体 --> <List></List> </template> <script lang="ts"> // 导入子组件 import Search from '../components/2.1 热门搜索组件.vue' import List from '../components/2.2 图书列表.vue' import { reactive } from 'vue'; export default { // 注册组件 components:{ Search, List }, setup() { // 定义“ 可能想搜索 ” 部分的数据,传到子组件里面 // (本来图书列表页哪里也需要在父组件定义数据传过去的,但是写的时候,还没有想到,所以就直接在子组件写了,比较推荐用以下这种方式传过去) const lists = reactive(["vue2","vue3","react","node.js","ES6","MySql"]) return { lists } } } </script> <style> /* 头部 */ .head{ display: flex; justify-content: space-between; /* border: 1px solid red; */ } .textbox{ width: 250px; height: 40px; background-color: #eeeeee; border-radius: 20px; line-height: 40px; } .textbox svg{ vertical-align: middle; margin-left: 5px; } .textbox input{ font-size: 16px; border: none; outline: none; background-color: #eeeeee; } .screen{ margin-right: 10px; line-height: 40px; } /* 副头部 */ .Deputy_head{ display: flex; justify-content: space-between; margin: 20px 10px; } /* 热门搜索 */ .hot_search { width: 90%; height: 120px; margin: auto; display: flex; flex-wrap: wrap; justify-content: space-around; background-color: #f2f2f2; border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; } </style>
2.5、运行结果
结果1:展示图书列表
结果2:点击随意一本图书都可以,进入该详情页,因为已经实现了动态化
三、使用Vue 组件(component)完成一个精美的日历
3.1、组件A(天数)
<!-- 本组件用于接收父组件遍历过来的天数 --> <template lang=""> <div> {{day}} </div> </template> <script lang="ts"> export default { // 接收参数数据 props:['day'] } </script> <style scoped> </style>
3.2、组件B(选择年份)
<!-- 本组件用于:定义年份 --> <template lang=""> <div class="ya-box"> <!-- 遍历数据 --> <div class="year" v-for="(item, i) in list" :key="i"> <!-- 挖个坑,定义坑的名称,把年份数据传到父组件里面 --> <slot name="cc" :data="item"></slot> </div> </div> </template> <script lang="ts"> import { reactive } from 'vue'; export default { setup() { // 定义年份的数据(当时没想到可以用循环遍历,所以先随意的定死了一些数据) const list = reactive([ { year: '2015' }, { year: '2016' }, { year: '2017' }, { year: '2018' }, { year: '2019' }, { year: '2020' }, { year: '2021' }, { year: '2022' }, { year: '2023' }, { year: '2024' }, { year: '2025' } ]); // 循环添加多个年份,从2026年开始到5000年结束(年份区间可以自定义的) for (let i = 2026; i<5000;i++) { // 循环添加到list数组里面,强转i为字符串添加 list.push({ year: String(i) }) } // 暴露出去页面 return { list } } } </script> <style scoped> .ya-box{ width: 100%; height: 340px; /* border: 1px solid #eeeeee; */ overflow-y: scroll; overflow-x: hidden; } .year { width: 100%; height: 30px; /* border: 1px solid lawngreen; */ line-height: 30px; margin: 20px 0; font-weight: bold; cursor: pointer; } </style>
3.3、父组件
<!-- 本组件为日历组件的父组件 --> <template> <div class="big-box"> <!-- 左边的日历,选天数 --> <div id="left-box"> <!-- 头部 --> <div class="ri-head" style="cursor: pointer;"> <p style="color: #b2ebf2;padding-top: 15px;font-size: 16px;" @click="showYear()">{{ year }}年</p> <p>{{ month }}月{{ day }}日 星期{{ week }}</p> </div> <!-- 天数的容器 --> <div class="ri-box"> <!-- 左右切换月份 --> <div class="riBox-head"> <!-- 点击这个为上个月 --> <svg t="1667840633451" @click="nextorshang(1)" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5160" width="20" height="20"> <path d="M677.391515 873.916768c-7.86101 0-15.618586-2.999596-21.617778-8.895354L324.473535 533.721212c-11.998384-11.894949-11.998384-31.340606 0-43.235555L655.670303 159.288889c5.999192-5.999192 13.756768-8.895354 21.617778-8.895354 7.757576 0 15.618586 2.999596 21.617778 8.895354 11.894949 11.894949 11.894949 31.237172 0 43.235555L389.223434 512.103434 698.905859 821.785859c11.894949 11.998384 11.894949 31.340606 0 43.235555-5.895758 5.895758-13.756768 8.895354-21.514344 8.895354z m0 0" fill="#2c2c2c" p-id="5161"></path> </svg> <!-- 日期 --> <span>{{ year }}年{{ month }}月</span> <!-- 点击这个为下个月 --> <svg t="1667840592593" @click="nextorshang(0)" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4143" width="20" height="20"> <path d="M307.6 104.6c-14.2 14.2-14.2 37.2 0 51.4L655 503.4c2.8 2.9 2.8 7.5 0 10.3L307.6 861.2c-14.2 14.2-14.2 37.2 0 51.4 14.2 14.2 37.2 14.2 51.4 0l347.4-347.4c15.6-15.6 23.4-36 23.4-56.5s-7.8-41-23.4-56.5L359 104.6c-14.2-14.2-37.2-14.2-51.4 0z" p-id="4144" fill="#2c2c2c"></path> </svg> </div> <!-- 星期 --> <div class="riBox-mian"> <span>一</span> <span>二</span> <span>三</span> <span>四</span> <span>五</span> <span>六</span> <span>日</span> </div> <!-- 天数 --> <div v-for="item in list" :key="item.i2" style="cursor: pointer;"> <!-- 子组件:点击某一天的时候,切换过去,注意添加类,条件为:当前天等于循环过来的某一天 --> <Ri @click="clcikhmrcs(item.day)" :day="item.day" class="ri-st" :class="{ day_active: day == item.day }"></Ri> </div> </div> </div> <!-- 右边 --> <div id="right-box" style="display: none;margin-left: 50px;"> <div class="ri-head" style="cursor: pointer;"> <p style="color: #fff;padding-top: 15px;font-size: 16px;">{{ year }}年</p> <p style="color: #aae9f1;">{{ month }}月{{ day }}日 星期{{ week }}</p> </div> <div class="ri-box"> <!-- 子组件 --> <Ri_year> <!-- 包含了一个容器,负责装年份的数据 --> <!-- 以下用了具名插槽#cc(与子组件的name必须一致)接受数据 --> <template #cc="{ data }"> <div :class="{ year_active: year == data.year }" @click="clickYear(data.year)"> {{ data.year }} </div> </template> </Ri_year> </div> </div> </div> </template> <script lang="ts"> // 导入子组件 import Ri from "../components/3.1 日历.vue"; import Ri_year from "../components/3.2 日历选年份.vue"; import { reactive, toRefs } from 'vue' export default { // 注册组件 components: { Ri, Ri_year }, setup() { // arr数组负责把获取到的星期数(阿拉伯数字)转为大写 const arr = ["日", "一", "二", "三", "四", "五", "六"]; // obj数组负责存储所有的天数、年份、月份、某天的数、星期数 const obj: any = reactive({ list: [], year: "", month: 0, day: "", week: "" }) // createyueday方法是根据传入的年份和月份判断该年份是闰年还是平年 function createyueday(n: any, yue: any) { if ((n % 4 == 0 && !(n % 100 == 0)) || n % 400 == 0) { days('闰年', yue) // console.log('闰年') } else { days('平年', yue) // console.log('平年') } // 把年份和月份重新赋值给obj对象中的月份和年份,用于在页面上显示 obj.year = n; obj.month = yue; } // days方法主要是用于判断闰年和平年中的2月份的天数,需要传入闰年或平年、月份两个参数 function days(run: any, yue: any) { // 定义一个空数组,用于存储循环过后的所有天数 let arr: any = [] // 然后再加以判断,如果是闰年中的2月份 if (yue == 2 && run == '闰年') { // 闰年的2月有29天,然后接收xunhuanday方法传过来的数组赋值给arr这个空数组里 obj.list = xunhuanday(29, arr) } else if (yue == 2 && run == '平年') { // 平年中的2月份 // 有28天 obj.list = xunhuanday(28, arr) } else if (yue == 4 || yue == 6 || yue == 9 || yue == 11) { // 小月份 // 只有30天 obj.list = xunhuanday(30, arr) } else { // 大月份 // 有31天 obj.list = xunhuanday(31, arr) } } // xunhuanday用于接收具体的一个月结束天数进行循环,把一个月具体的多少天存储到数组里面 function xunhuanday(index: any, arr: any) { // 例如是闰年的二月份,传进来的就是29,所以从0开始,到29结束 for (let i = 0; i < index; i++) { // 添加数据到arr数组里面,把天数存储进去 arr.push({ day: i + 1 }) } // 最后返回数组 return arr } // nextorshang方法用于切换月份,如果i2传进来的是1,就代表是上个月,传进来的是0,就代表下个月 function nextorshang(i2: any) { if (i2 == 1) { // 下个月 // 月份-1 obj.month-- // 一直减,如果月份小于1月 if (obj.month < 1) { // 就进去上一年了,所以年份需要-1 obj.year-- // 重新赋值年份,然后月份默认为上一年的12月 createyueday(obj.year, 12); } // 如果月份没有小于1月的话,就直接输出该年份和该月份 createyueday(obj.year, obj.month) } else { // 下一个 // 月份+1 obj.month++ // 同理,如果月份大于12月就进入下一年 if (obj.month > 12) { // 年份+1 obj.year++ // 重新赋值,下一年的话,默认月份为1月 createyueday(obj.year, 1); } // 不大于12月就输出该年份和该月份 createyueday(obj.year, obj.month) } // 无论点击上个月还是下个月,切换之后的天数就默认为该月的1号 obj.day = 1; // 星期数也是需要指定当前的年月日来获取星期数,所以把当前obj的年月日传进去 obj.week = arr[new Date(obj.year + "-" + obj.month + "-" + 1).getDay()]; console.log(obj.week); // 获取到的星期日为0,所以需要重新赋值星期数为7 if (obj.week == 0) { obj.week = 7; } } // clcikhmrcs方法用于点击某一天时查看该天的具体日期数,传入具体的哪一天 function clcikhmrcs(day: any) { // obj数组的天数重新赋值,改变当前天数 obj.day = day; // 星期数也需要重新赋值,重新传天数进去 obj.week = arr[new Date(obj.year + "-" + obj.month + "-" + day).getDay()]; } // 点击头部中的年份显示选择年份的日历,把显示天数的日历隐藏 function showYear() { // <HTMLDivElement>:ts的写法,用于操作dom元素时使用,否则会报错 (<HTMLDivElement>document.getElementById("right-box")).style.display = "block"; (<HTMLDivElement>document.getElementById("left-box")).style.display = "none"; } // clickYear方法用于选择年份来查看具体的日期,传入选择的某一年份 function clickYear(year: any) { console.log(year); // 把obj数组中的年份重新赋值 obj.year = year; // 把重新赋值后的年份,和默认1月的数据渲染到页面上 createyueday(obj.year, 1); // 天数也是默认1号 obj.day = 1; // 重新传入年月日查询星期数 obj.week = arr[new Date(obj.year + "-" + obj.month + "-" + 1).getDay()]; // 选择完年份后,隐藏选择年份的日历,显示天数的日历出现 (<HTMLDivElement>document.getElementById("right-box")).style.display = "none"; (<HTMLDivElement>document.getElementById("left-box")).style.display = "block"; } // 初始化日历,页面加载时,就显示以下的数据 // 显示当前的年份、月份、天数、星期数 createyueday(new Date().getFullYear(), new Date().getMonth() + 1) obj.day = new Date().getDate() obj.week = arr[new Date().getDay()]; // 暴露出去 return { nextorshang, ...toRefs(obj), clcikhmrcs, clickYear, showYear } } } </script> <style > .big-box { width: 750px; padding: 20px; /* border: 1px solid navy; */ margin: auto; display: flex; justify-content: space-evenly; } .ri-head { width: 360px; height: 80px; margin: auto; background-color: #00bcd4; color: #fff; } .ri-head p { text-align: left; margin-left: 20px; font-size: 25px; margin-top: -10px; } .ri-box { display: flex; flex-wrap: wrap; width: 358px; border: 1px solid #eee; margin: auto; padding-bottom: 20px; } .ri-st { width: 30px; height: 30px; line-height: 30px; text-align: center; margin: 10px; } .riBox-head, .riBox-mian { width: 100%; display: flex; justify-content: space-between; margin: auto; margin-top: 20px; padding: 0px 20px; /* border: 1px solid red; */ } .riBox-mian { font-size: 14px; color: #909090; margin-left: -2px; justify-content: space-around; padding: 0px; margin-bottom: 10px; } .day_active { background-color: #00bcd4; color: #fff; border-radius: 15px; } .year_active { color: #fff; background-color: #00bcd4; } </style>
3.4、运行结果
结果1:展示日期
结果2:选择年份,展示该年份的日期
四、使用动态插槽完成一个选项卡,点击卡片名称时动态切换。
4.1、子组件A(定义选项卡的数据)
<!-- 本组件用于:向父组件传值 --> <template lang=""> <!-- 遍历三个数组对象 --> <div v-for="(item,i) in list"> <!-- slot标签相当于在子组件里面挖一个坑,到父组件里填上 --> <!-- 在这里需要定义一个名称,然后把遍历出来的数据传到父组件里面 --> <slot name="s1" :data="item"></slot> </div> <div v-for="(item,i) in list2"> <slot name="s2" :data="item"></slot> </div> <div v-for="(item,i) in list3"> <slot name="s3" :data="item"></slot> </div> </template> <script lang="ts"> import { reactive } from 'vue' export default { setup() { // 定义选项卡的数据 const list = reactive([ { name: 'vue1' }, { name: 'vue1' }, { name: 'vue1' } ]) const list2 = reactive([ { name: 'vue2' }, { name: 'vue2' }, { name: 'vue2' } ]) const list3 = reactive([ { name: 'vue3' }, { name: 'vue3' }, { name: 'vue3' } ]) // 暴露出去 return { list, list2, list3 } } } </script> <style scoped> </style>
4.2、父组件
<template lang=""> <div class="big"> <!-- 选项卡按钮 --> <!-- 点击按钮时,修改变量s的值,目的是:让s的值变为子组件那边所需要的值,看用户需要哪个数据,就点击哪个按钮,达到选项卡的效果 --> <button style="margin-left: 0px;" @click="s = 's1'" :class="{active: s === 's1'}">vue1</button> <button @click="s = 's2'" :class="{active: s === 's2'}">vue2</button> <button @click="s = 's3'" :class="{active: s === 's3'}">vue3</button> <div class="big_box"> <!-- 导入子组件 --> <Ez > <!-- # 相当于 v-slot --> <!-- 这个为作用域插槽 --> <!-- [s]定义的目的就是为了让具名发生变化,如果为s1,就传子组件那边对应的name --> <!-- 然后在这里接受子组件传过来的数据 --> <template #[s]="{data}"> <div class="item-box"> <!-- 输出数据到页面上 --> {{data.name}} </div> </template> </Ez> </div> </div> </template> <script lang="ts"> import Ez from "../components/4.1 动态插槽之儿子组件.vue"; import { ref } from 'vue' export default { components: { Ez }, setup() { let s = ref('s1') return { s } } } </script> <style scoped> .big{ width: 350px; height: 390px; background-color: #636d76; margin: auto; } button{ width: 100px; height: 40px; background-color: #474b54; color: #ece6b2; border: none; margin-left: 10px; margin-top: 10px; } .big_box{ width: 91.3%; height: 330px; background-color: #fff; margin: auto; } .item-box { width: 80%; padding: 10px; margin: auto; border-bottom: 1px solid #d7dee1; } .active{ background-color: #fff; color: #333; } </style>
4.3、运行结果:
五、使用动态组件完成一个选项卡,定义3个不同的组件,点击卡片名称时动态切换。
5.1、子组件A(第一页)
<template> <h3>测试KeepAlive组件强制被切换掉的组件仍然保持“存活”的状态</h3> <h1>{{s}}</h1> <h2>{{s}}</h2> <h3>{{s}}</h3> <hr> <button @click="s++">点我+1哦</button> </template> <script lang="ts"> import {ref} from 'vue' export default { // 组件里的name属性 name: 'a', setup () { const s = ref(1) return { s } } } </script> <style scoped> h1,h2,h3{ background-color: #e2e2e2; color: #777; width: 90%; margin: auto; margin-top: 20px; } </style>
5.2、子组件B(第二页)
<template> <h3>测试KeepAlive组件强制被切换掉的组件仍然保持“存活”的状态</h3> <h1>{{s}}</h1> <h2>{{s}}</h2> <h3>{{s}}</h3> <hr> <button @click="s++">点我+1哦</button> </template> <script lang="ts"> import {ref} from 'vue' export default { // 组件里的name属性 name: 'b', setup () { const s = ref(10) return { s } } } </script> <style scoped> h1,h2,h3{ background-color: #e2e2e2; color: #777; width: 90%; margin: auto; margin-top: 20px; } </style>
5.3、子组件C(第三页)
<template> <h3>测试KeepAlive组件强制被切换掉的组件仍然保持“存活”的状态</h3> <h1>{{s}}</h1> <h2>{{s}}</h2> <h3>{{s}}</h3> <hr> <button @click="s++">点我+1哦</button> </template> <script lang="ts"> import {ref} from 'vue' export default { // 组件里的name属性 name: 'c', setup () { const s = ref(100); return { s } } } </script> <style scoped> h1,h2,h3{ background-color: #e2e2e2; color: #777; width: 90%; margin: auto; margin-top: 20px; } </style>
5.4、父组件
<template > <div class="box"> <div class="box-head"> <div class="bh-min" style="border-radius: 0px 0px 0px 20px;" @click="componentId='A'" :class="{active: componentId === 'A'}"> <svg t="1667842015073" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6350" width="20" height="20"><path d="M527.247 204.247c113.891 0 227.885 0.717 341.777-0.307 60.373-0.511 88.923 25.48 88.31 87.491-1.434 139.474 0.408 278.947-0.82 418.42-0.716 78.18-31.926 107.241-111.333 107.343-218.573 0.307-437.044 0.307-655.618-0.204-77.667-0.205-124.84-46.764-125.25-123.613-0.716-125.557-0.511-251.114-0.204-376.568 0.204-81.454 30.289-111.845 114.403-112.664 116.245-1.126 232.49-0.307 348.735-0.307v0.41z m-9.21 558.611c109.287 0 218.676-1.33 327.963 0.614 41.443 0.716 58.225-12.382 57.304-55.667-2.252-104.58-0.307-209.364-1.33-314.045-0.103-17.09 9.414-40.625-12.485-49.834-19.954-8.391-32.642 10.13-47.07 21.693-96.906 77.36-195.653 152.572-291.023 231.774-31.517 26.196-51.573 25.275-82.272-0.102-97.11-80.533-197.084-157.484-295.012-237.095-13.098-10.642-25.378-23.74-41.648-19.136-21.08 6.038-13.2 27.22-13.303 42.057-0.716 99.975 1.33 200.052-0.716 300.027-1.126 56.485 23.536 80.328 78.69 79.816 106.831-0.818 213.867-0.204 320.902-0.102zM139.525 262.677c19.851 18.317 25.991 24.763 32.95 30.29 60.885 48.298 121.259 97.211 182.86 144.384 159.837 122.488 160.246 122.488 316.707-2.148 66.41-52.904 131.492-107.343 211.205-172.628-255.411 0.102-490.562 0.102-743.722 0.102z" fill="#7061a7" p-id="6351"></path></svg> <span>选项卡 1</span> </div> <div class="bh-min" @click="componentId='B'" :class="{active: componentId === 'B'}"> <svg t="1667842222005" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7505" width="20" height="20"><path d="M1016.832 606.208q2.048 12.288-1.024 29.696t-10.24 35.328-17.408 32.256-22.528 20.48-21.504 6.144-20.48-4.096q-10.24-3.072-25.6-5.632t-31.232-1.024-31.744 6.656-27.136 17.408q-24.576 25.6-28.672 58.368t9.216 62.464q10.24 20.48-3.072 40.96-6.144 8.192-19.456 16.896t-29.184 15.872-33.28 11.264-30.72 4.096q-9.216 0-17.408-7.168t-11.264-15.36l-1.024 0q-11.264-31.744-38.4-54.784t-62.976-23.04q-34.816 0-62.976 23.04t-39.424 53.76q-5.12 12.288-15.36 17.92t-22.528 5.632q-14.336 0-32.256-5.12t-35.84-12.8-32.256-17.92-21.504-20.48q-5.12-7.168-5.632-16.896t7.68-27.136q11.264-23.552 8.704-53.76t-26.112-55.808q-14.336-15.36-34.816-19.968t-38.912-3.584q-21.504 1.024-44.032 8.192-14.336 4.096-28.672-2.048-11.264-4.096-20.992-18.944t-17.408-32.768-11.776-36.864-2.048-31.232q3.072-22.528 20.48-28.672 30.72-12.288 55.296-40.448t24.576-62.976q0-35.84-24.576-62.464t-55.296-38.912q-9.216-3.072-15.36-14.848t-6.144-24.064q0-13.312 4.096-29.696t10.752-31.744 15.36-28.16 18.944-18.944q8.192-5.12 15.872-4.096t16.896 4.096q30.72 12.288 64 7.68t58.88-29.184q12.288-12.288 17.92-30.208t7.168-35.328 0-31.744-2.56-20.48q-2.048-6.144-3.584-14.336t1.536-14.336q6.144-14.336 22.016-25.088t34.304-17.92 35.84-10.752 27.648-3.584q13.312 0 20.992 8.704t10.752 17.92q11.264 27.648 36.864 48.64t60.416 20.992q35.84 0 63.488-19.968t38.912-50.688q4.096-8.192 12.8-16.896t17.92-8.704q14.336 0 31.232 4.096t33.28 11.264 30.208 18.432 22.016 24.576q5.12 8.192 3.072 17.92t-4.096 13.824q-13.312 29.696-8.192 62.464t29.696 57.344 60.416 27.136 66.56-11.776q8.192-5.12 19.968-4.096t19.968 9.216q15.36 14.336 27.136 43.52t15.872 58.88q2.048 17.408-5.632 27.136t-15.872 12.8q-31.744 11.264-54.272 39.424t-22.528 64q0 34.816 18.944 60.928t49.664 37.376q7.168 4.096 12.288 8.192 11.264 9.216 15.36 23.552zM540.672 698.368q46.08 0 87.04-17.408t71.168-48.128 47.616-71.168 17.408-86.528-17.408-86.528-47.616-70.656-71.168-47.616-87.04-17.408-86.528 17.408-70.656 47.616-47.616 70.656-17.408 86.528 17.408 86.528 47.616 71.168 70.656 48.128 86.528 17.408z" p-id="7506" fill="#7061a7"></path></svg> <span>选项卡 2</span> </div> <div class="bh-min" @click="componentId='C'" :class="{active: componentId === 'C'}"> <svg t="1667842294039" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8570" width="20" height="20"><path d="M639.892491 415.930119 383.935495 415.930119c-17.717453 0-31.994625-14.277171-31.994625-31.994625s14.277171-31.994625 31.994625-31.994625L639.892491 351.94087c17.717453 0 31.994625 14.277171 31.994625 31.994625S657.609945 415.930119 639.892491 415.930119z" p-id="8571" fill="#7061a7"></path><path d="M579.17151 543.908618 383.935495 543.908618c-17.717453 0-31.994625-14.277171-31.994625-31.994625S366.390055 479.919368 383.935495 479.919368l195.236015 0c17.717453 0 31.994625 14.277171 31.994625 31.994625S596.888964 543.908618 579.17151 543.908618z" p-id="8572" fill="#7061a7"></path><path d="M962.246934 447.924744c0-211.74937-200.912481-383.935495-447.924744-383.935495S66.225433 236.175374 66.225433 447.924744c0 116.453553 62.957164 226.026541 172.874181 300.680665 14.621199 9.976818 34.574836 6.192508 44.379641-8.428691 9.976818-14.621199 6.192508-34.574836-8.428691-44.379641-92.027549-62.441122-144.835881-152.74853-144.835881-247.700319 0-176.486477 172.186125-319.946246 383.935495-319.946246s383.935495 143.631782 383.935495 319.946246-172.186125 319.946246-383.935495 319.946246c-2.064169 0-3.612296 0.688056-5.504452 1.204099-15.137242-2.752226-30.446498 5.160423-35.778935 20.125651-6.192508 17.373425-46.44381 46.615824-94.091718 73.794053 17.373425-58.140769 9.116748-70.697799 3.440282-78.954477-6.70855-9.976818-17.889467-15.997312-29.930455-15.997312-17.717453 0-31.994625 14.277171-31.994625 31.994625 0 5.84848 1.548127 11.180917 4.300353 15.997312-3.268268 18.233496-17.201411 60.892995-33.026709 99.768184-4.988409 12.040988-2.064169 25.974131 7.396607 35.090879 6.020494 5.84848 14.105157 8.944734 22.18982 8.944734 4.300353 0 8.77272-0.860071 13.073072-2.752226 36.466991-16.341341 147.588107-69.149672 187.667395-125.570301C765.290778 828.075928 962.246934 657.609945 962.246934 447.924744z" p-id="8573" fill="#7061a7"></path></svg> <span>选项卡 3</span> </div> </div> <div class="box-mian"> <!-- KeepAlive: (接地气说法)阻止组件卸载,从a页面 切换到b页面 但是a页面输入或保存的的数据不会被销毁--> <!-- 可以让强制被切换掉的组件仍然保持“存活”的状态 --> <!-- 包含(include)/排除(exclude) --> <!-- 根据组件的 name 选项进行匹配,所以组件如果想要条件性地被 KeepAlive 缓存,就必须显式声明一个 name 选项。 --> <!-- :is --> <!-- 被传给 :is 的值可以是以下几种: 被注册的组件名 导入的组件对象 --> <KeepAlive include="a,b"> <component :is="components[componentId]"></component> </KeepAlive> </div> </div> </template> <script lang="ts" setup> import { ref } from 'vue'; import A from '../components/5.1 动态组件之A组件.vue'; import B from '../components/5.2 动态组件之B组件.vue'; import C from '../components/5.3 动态组件之C组件.vue'; let components:any = { A,B,C } const componentId = ref("A"); </script> <style scoped> .box{ width: 45%; height: 250px; border-bottom: 3px solid #73679e; margin: auto; } .box-head{ width: 100%; height: 50px; display: flex; color: #333; background-color: #eaeaea; border-radius: 0px 20px 0px 20px; } .bh-min{ width: 20%; height: 100%; /* border: 1px solid rebeccapurple; */ } .bh-min svg{ vertical-align: middle; } .bh-min span{ vertical-align: middle; margin-left: 10px; line-height: 50px; } .active{ fill:#fff; color: #fff; background-color: #795da6; } .active svg path{ fill: #fff; } .box-mian{ width: 100%; height: 200px; /* border: 1px solid lawngreen; */ } </style>