一、定义一个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>

5.5、运行结果

Vue3 —— 组件练习题(附源码)的更多相关文章

  1. 基于vue与vux做的可滑动tab组件(附源码)

    背景 前不久,刚完成了一个商品列表+购物车功能的页面,因为一级商品分类在顶部tab中显示,可滑动,间距可定制,如下图所示: 定制的tab需求如下: 1. 每个tab-item的间距是相同的,可定制 2 ...

  2. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)

    前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...

  3. C#轻量级通通讯组件StriveEngine —— C/S通信开源demo(2) —— 使用二进制协议 (附源码)

    前段时间,有几个研究ESFramework通信框架的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好友关 ...

  4. 日志组件Log2Net的介绍和使用(附源码开源地址)

    Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...

  5. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

  6. 轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)

    在网络上,交互的双方基于TCP或UDP进行通信,通信协议的格式通常分为两类:文本消息.二进制消息. 文本协议相对简单,通常使用一个特殊的标记符作为一个消息的结束. 二进制协议,通常是由消息头(Head ...

  7. ASP.NET程序读取二代身份证(附源码)

    原文:ASP.NET程序读取二代身份证(附源码) 一般来说winform应用程序解决这个问题起来时很容易的,web应用程序就麻烦一点了. 这里我说说我的解决思路: 一.你必要有联机型居民身份证阅读器一 ...

  8. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  9. 微服务8:通信之RPC实践篇(附源码)

    ★微服务系列 微服务1:微服务及其演进史 微服务2:微服务全景架构 微服务3:微服务拆分策略 微服务4:服务注册与发现 微服务5:服务注册与发现(实践篇) 微服务6:通信之网关 微服务7:通信之RPC ...

  10. Vue过渡和动画效果展示(案例、GIF动图演示、附源码)

    前言 本篇随笔主要写了Vue过渡和动画基础.多个元素过渡和多个组件过渡,以及列表过渡的动画效果展示.详细案例分析.GIF动图演示.附源码地址获取. 作为自己对Vue过渡和动画效果知识的总结与笔记. 因 ...

随机推荐

  1. KingbaseES CTID 与 Oracle ROWID

    熟悉oracle的人都知道ROWID可用于快速的数据访问,KingbaseES 由于自身MVCC机制的原因,ctid 作为 oracle rowid 的替代方案不合适,但currtid 还是基本可以满 ...

  2. 【读书笔记】C#高级编程 第二十五章 事务处理

    (一)简介 事务的主要特征是,任务要么全部完成,要么都不完成. (二)概述 事务由事务管理器来管理和协调.每个影响事务结果的资源都由一个资源管理器来管理.事务管理器与资源管理器通信,以定义事务的结果. ...

  3. Unity-编辑器拓展之GUILayout,EditorGUILayout布局 { }

    Unity 脚本 API 中文版 链接: https://docs.unity3d.com/cn/2019.4/ScriptReference/ 创建自定义窗口 public class MyWind ...

  4. SDUT 2022 Autumn Team Contest 7th

    1.J题:给你T组数据,每一组数据给你一个区间,让你求这个区间的范围,区间的起始时间和终止时间可能被包含或重复 思路:思路的话,就是直接把给定的两个区间的之间的数包括端点存到vector去重,然后直接 ...

  5. [Python]-sklearn模块-机器学习Python入门《Python机器学习手册》-02-加载数据:加载数据集

    <Python机器学习手册--从数据预处理到深度学习> 这本书类似于工具书或者字典,对于python具体代码的调用和使用场景写的很清楚,感觉虽然是工具书,但是对照着做一遍应该可以对机器学习 ...

  6. 微服务低代码Serverless平台(星链)的应用实践

    导读 星链是京东科技消金基础研发部研发的一款研发效能提升的工具平台,面向后端服务研发需求,尤其是集成性.场景化.定制化等难度不太高.但比较繁琐的需求,如服务前端的后端(BFF).服务流程编排.异步消息 ...

  7. 安装vm,在vm中安装windows10操作系统。

    步骤:双击打开虚拟机文件 根据向导安装  下一步 然后等待安装 安装好了后点击许可证 ZF3R0-FHED2-M80TY-8QYGC-NPKYF YF390-0HF8P-M81RQ-2DXQE-M2U ...

  8. 微服务系列之Api文档 swagger整合

    1.前言 微服务架构随之而来的前后端彻底分离,且服务众多,无论是前后端对接亦或是产品.运营翻看,一个现代化.规范化.可视化.可尝试的文档是多么重要,所以我们这节就说说swagger. Swagger是 ...

  9. 在Kuboard上安装 Ingress Controller

    快速安装 # 只在 master 节点执行 kubectl apply -f https://kuboard.cn/install-script/v1.18.x/nginx-ingress.yaml ...

  10. WPF 的内部世界(控件与布局)

    目录 一.控件与布局 前言 为什么要写WPF呢? 我一开始算是比较抵触WPF的,因为用的人少吗.感觉都是窗体应用能和Winform有什么区别.可是我错了,非常感谢我的讲师,给我推荐刘铁猛的<深入 ...