昨日复习
- 购物车完整案例-父传子 props- 子传父 自定义事件
- 动态组件-多个不同的组件要显示在一个位置
```html
// 变量- 组件名称-AChild1-AChild2
2. 组件的缓存
> 组件被缓存了,组件没有被销毁。Vue的内置组件 keep-alive
```vue
<keep-alive>
// 组件-
</keep-alive>
保留了组件的实例,组件的虚拟dom,真实dom销毁了
组件只会创建一次,created只会执行一次
提供了两个新的钩子函数-激活事件- 休眠事件
插槽
占位
<template>
<slot></slot>
</template>
填补内容
<child>
// 填补内容
</child>
匿名插槽
<slot></slot> // 没有起name 匿名插槽
具名插槽
<slot name="before"></slot>
填补的时候需要指定名称
<child> // 新的语法 <template v-slot:before> 123 </template> // 旧的语法 <template slot="before">123</template> </child>
后备内容
后备-没有人传入插槽内容的时候,后备内容回显示
<slot>后备内容</slot>
- 作用域插槽
父组件传插槽内容的时候想要使用子组件的数据
先在子组件传出你想让父组件用的数据
<slot a="1" b="2" c="3" :d="变量"></slot> <slot name="after" a="1" b="2" c="3" :d="变量"></slot>
传插槽内容时,获取变量
<child> // obj是传出的所有的属性的集合 <template v-slot:after="obj"> <template slot="after" slot-scope="obj"> <div > a: {{ obj.a }} b: {{ obj.b }} </div> </template> </child>
作用域插槽 - 匿名插槽- 具名插槽
用具名插槽的时候
<child> <div slot="名字" slot-scope="变量名"> <template v-slot:名字="变量名"> </child>
自定义指令
开发者也可以封装指令
局部注册和全局注册 ```javascript export default { directives: { “focus”: {
// 指令描述 inserted(el, options) { // 此时表示此指令作用的dom元素已经被插入到页面上 }
} }
}
.sync 修饰符
> 子传父- 1. 子组件触发 2.父组件监听
.sync- 1.子组件触发
<a name="DpBBM"></a>
### 3.0 案例-tabbar-初始化项目
目标: 创建项目文件夹, 引入字体图标, 下载bootstrap, less, less-loader@5.0.0 axios, 在App.vue注册组件
- 需求: 从0新建项目, 拆分组件, 创建使用
组件分析:
- 组件拆分:
- MyHeader.vue – ==复用之前的==
- MyTabBar.vue – 底部导航
- MyTable.vue – 封装表格
- 三个页面
- -MyGoodsList.vue – 商品页
- MyGoodsSearch.vue – 搜索页
- -MyUserInfo.vue – 用户信息页
思路分析:<br /> ①: vue create tabbar-demo<br /> ②: yarn add less less-loader@5.0.0 -D<br /> ③: yarn add bootstrap axios 并在main.js 引入和全局属性<br /> ④: 根据需求-创建需要的页面组件<br /> ⑤: 把昨天购物车案例-封装的MyHeader.vue文件复制过来复用<br /> ⑥: 从App.vue – 引入组织相关标签<br />新建工程:<br />vue create tabbar-demo<br />yarn add less less-loader@5.0.0 -D<br />yarn add bootstrap axios<br />在main.js中引入bootStrap.css和字体图标样式<br />import "bootstrap/dist/css/bootstrap.css"<br />import "./assets/fonts/iconfont.css"<br />创建/复制如下文件<br />从昨天案例中-直接复制过来components/MyHeader.vue<br />components/MyTabBar.vue<br />views/MyGoodsList.vue<br />views/MyGoodsSearch.vue<br />views/MyUserInfo.vue<br />components/MyTable.vue
<a name="Tlrz9"></a>
### 3.1 案例-tabbar-底部封装
目标: 实现MyTabBar.vue组件
- 需求: 把底部导航也灵活封装起来
分析:<br /> ①: 基本标签+样式(md里复制)<br /> ②: 为tabbar组件指定数据源<br /> ③: 数据源最少2个, 最多5个(validator)<br /> ④: 从App.vue给MyTabBar.vue传入底部导航的数据<br /> ⑤: MyTabBar.vue中循环展示<br />App.vue-数组准备
```json
tabList: [
{
iconText: "icon-shangpinliebiao",
text: "商品列表",
componentName: "MyGoodsList"
},
{
iconText: "icon-sousuo",
text: "商品搜索",
componentName: "MyGoodsSearch"
},
{
iconText: "icon-user",
text: "我的信息",
componentName: "MyUserInfo"
}
]
MyTabBar.vue - 标签模板
<template>
<div class="my-tab-bar">
<div class="tab-item">
<!-- 图标 -->
<span class="iconfont"></span>
<!-- 文字 -->
<span></span>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
.my-tab-bar {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 50px;
border-top: 1px solid #ccc;
display: flex;
justify-content: space-around;
align-items: center;
background-color: white;
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
}
}
.current {
color: #1d7bff;
}
</style>
MyTabBar.vue正确代码
<template>
<div class="my-tab-bar">
<div class="tab-item" v-for="(item, index) in tabList" :key="index">
<!-- 图标 -->
<span :class="`iconfont ${item.iconText}`"></span>
<!-- 文字 -->
<span>{{ item.text }}</span>
</div>
</div>
</template>
<script>
export default {
// props: ["tabList"], // 最基本的接收 但是不能校验
props: {
tabList: {
type: Array,
required: true, // 要求必填
// 校验的意思
validator(value) {
// 最低的长度 2 最大的长度是 5
if (value.length >= 2 && value.length <= 5) {
return true; // 表示通过了校验
} else {
return false; // 表示没有通过校验 就会报错
}
},
},
},
};
</script>
<style lang="less" scoped>
.my-tab-bar {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 50px;
border-top: 1px solid #ccc;
display: flex;
justify-content: space-around;
align-items: center;
background-color: white;
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
}
}
.current {
color: #1d7bff;
}
</style>
3.2 案例-tabbar-底部高亮
目标: 点击底部导航实现高亮效果
- 需求: 点击底部实现高亮效果
分析:
①: 绑定点击事件, 获取点击的索引
②: 循环的标签设置动态class, 遍历的索引, 和点击保存的索引比较, 相同则高亮
效果演示:
MyTabBar.vue(==正确代码==)
<template>
<div class="my-tab-bar">
<div
class="tab-item"
v-for="(item, index) in tabList"
:class="{ current: index === activeIndex }"
@click="changeIndex(index)"
:key="index"
>
<!-- 图标 -->
<span :class="`iconfont ${item.iconText}`"></span>
<!-- 文字 -->
<span>{{ item.text }}</span>
</div>
</div>
</template>
<script>
export default {
// props: ["tabList"], // 最基本的接收 但是不能校验
props: {
tabList: {
type: Array,
required: true, // 要求必填
// 校验的意思
validator(value) {
// 最低的长度 2 最大的长度是 5
if (value.length >= 2 && value.length <= 5) {
return true; // 表示通过了校验
} else {
return false; // 表示没有通过校验 就会报错
}
},
},
},
data() {
return {
activeIndex: 0, // 默认第一个激活
};
},
methods: {
changeIndex(index) {
this.activeIndex = index;
},
},
};
</script>
<style lang="less" scoped>
.my-tab-bar {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 50px;
border-top: 1px solid #ccc;
display: flex;
justify-content: space-around;
align-items: center;
background-color: white;
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
}
}
.current {
color: #1d7bff;
}
</style>
3.3 案例-tabbar-组件切换
目的: 点击底部导航, 切换页面组件显示
需求: 点击底部切换组件
分析:
①: 底部导航传出动态组件名字符串到App.vue
②: 切换动态组件is属性的值为要显示的组件名
效果演示:
补充: 给内容div.app- 设置上下内边距
App.vue - 引入并注册
<template>
<div>
<MyHeader
:background="'blue'"
:fontColor="'white'"
title="TabBar案例"
></MyHeader>
<div class="main">
<component :is="comName"></component>
</div>
<MyTabBar :arr="tabList"
@changeCom="changeComFn"
></MyTabBar>
</div>
</template>
<script>
import MyHeader from "./components/MyHeader";
import MyTabBar from './components/MyTabBar'
import MyGoodsList from './views/MyGoodsList'
import MyGoodsSearch from './views/MyGoodsSearch'
import MyUserInfo from './views/MyUserInfo'
export default {
data() {
return {
comName: "MyGoodsList", // 默认显示的组件
tabList: [ // 底部导航的数据
{
iconText: "icon-shangpinliebiao",
text: "商品列表",
componentName: "MyGoodsList",
},
{
iconText: "icon-sousuo",
text: "商品搜索",
componentName: "MyGoodsSearch",
},
{
iconText: "icon-user",
text: "我的信息",
componentName: "MyUserInfo",
},
],
};
},
components: {
MyHeader,
MyTabBar,
MyGoodsList,
MyGoodsSearch,
MyUserInfo
},
methods: {
changeComFn(cName){
this.comName = cName; // MyTabBar里选出来的组件名赋予给is属性的comName
// 导致组件的切换
}
}
};
</script>
<style scoped>
.main{
padding-top: 45px;
padding-bottom: 51px;
}
</style>
MyTabBar.vue - 点击传递过来组件名
methods: {
btn(index, theObj) {
this.selIndex = index; // 点谁, 就把谁的索引值保存起来
this.$emit(“changeCom”, theObj.componentName); // 要切换的组件名传App.vue
},
},
3.4 案例-tabbar-商品列表
目标: 为MyGoodsList页面, 准备表格组件MyTable.vue-铺设展示数据
- 需求: 商品列表铺设页面
分析:
①: 封装MyTable.vue – 准备标签和样式
②: axios在MyGoodsList.vue请求数据回来
③: 请求地址: http://localhost:3000/goodsList
json-server启动json数据
{
"goodsList": [
{
"id": 1,
"goods_name": "Teenmix/天美意夏季专柜同款金色布女鞋6YF18BT6",
"goods_price": 298,
"tags": [
"舒适",
"透气"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 2,
"goods_name": "奥休斯(all shoes) 冬季保暖女士休闲雪地靴 舒适加绒防水短靴 防滑棉鞋子",
"goods_price": 89,
"tags": [
"保暖",
"防滑"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 3,
"goods_name": "初语秋冬新款毛衣女 套头宽松针织衫简约插肩袖上衣",
"goods_price": 199,
"tags": [
"秋冬",
"毛衣"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 4,
"goods_name": "佐露絲蕾丝衫女2020春秋装新款大码女装衬衫上衣雪纺衫韩版打底衫长袖",
"goods_price": 19,
"tags": [
"雪纺衫",
"打底"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 5,
"goods_name": "熙世界中长款长袖圆领毛衣女2022秋装新款假两件连衣裙女107SL170",
"goods_price": 178,
"tags": [
"圆领",
"连衣裙"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 6,
"goods_name": "烟花烫2021秋季装新品女装简约修身显瘦七分袖欧根纱连衣裙 花央",
"goods_price": 282,
"tags": [
"秋季新品",
"显瘦"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 7,
"goods_name": "韩都衣舍2021韩版女装秋装新宽松显瘦纯色系带长袖衬衫NG8201",
"goods_price": 128,
"tags": [
"韩都衣舍",
"长袖衬衫"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 8,
"goods_name": "预售纤莉秀大码女装胖妹妹秋装2020新款圆领百搭绣花胖mm休闲套头卫衣",
"goods_price": 128,
"tags": [
"预售",
"卫衣"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 9,
"goods_name": "莎密2022夏改良旗袍裙连衣裙修身复古时尚日常短款礼服旗袍",
"goods_price": 128,
"tags": [
"莎密",
"礼服"
],
"inputVisible": false,
"inputValue": ""
},
{
"id": 10,
"goods_name": "南极人秋冬韩版七彩棉加绒加厚一体保暖打底裤p7011",
"goods_price": 128,
"tags": [
"南极人",
"打底裤"
],
"inputVisible": false,
"inputValue": ""
}
]
}
④: 传入MyTable.vue中循环数据显示<br /> ⑤: 给删除按钮添加bootstrap的样式: btn btn-danger btn-sm<br />效果演示:<br />MyTable.vue - 准备table整个表格标签和样式(可复制)
<template>
<table class="table table-bordered table-stripped">
<!-- 表格标题区域 -->
<thead>
<tr>
<th>#</th>
<th>商品名称</th>
<th>价格</th>
<th>标签</th>
<th>操作</th>
</tr>
</thead>
<!-- 表格主体区域 -->
<tbody>
<tr >
<td>1</td>
<td>商品</td>
<td>998</td>
<td>xxx</td>
<td>xxx</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
name: 'MyTable'
}
</script>
<style scoped lang="less">
.my-goods-list {
.badge {
margin-right: 5px;
}
}
</style>
使用axios请求数据, 把表格页面铺设出来
main.js - 注册axios配置默认地址
import axios from “axios”;
axios.defaults.baseURL = “http://localhost:3000“;
MyGoodsList.vue - 使用axios请求数据, 把数据传入给MyTable.vue里循环铺设
MyTable.vue里正确代码
<template>
<table class="table table-bordered table-stripped">
<!-- 表格标题区域 -->
<thead>
<tr>
<th>#</th>
<th>商品名称</th>
<th>价格</th>
<th>标签</th>
<th>操作</th>
</tr>
</thead>
<!-- 表格主体区域 -->
<tbody>
<tr v-for="item in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.goods_name }}</td>
<td>{{ item.goods_price }}</td>
<td>{{ item.tags }}</td>
<td>
<button class="btn btn-danger btn-sm">删除</button>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
name: "MyTable",
props: {
list: {
type: Array,
required: true,
},
},
};
</script>
<style scoped lang="less">
.my-goods-list {
.badge {
margin-right: 5px;
}
}
</style>
MyGoodsList.vue代码
<template>
<div>
<my-table :list="list"></my-table>
</div>
</template>
<script>
import MyTable from "../components/MyTable.vue";
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3000";
export default {
components: {
MyTable,
},
data() {
return {
list: [], // 用来接收数据
};
},
created() {
this.getGoodsList();
},
methods: {
getGoodsList() {
axios.get("/goodsList").then(({ data }) => {
this.list = data; // 获取返回的数据
});
},
},
};
</script>
<style>
</style>
3.5_案例-tabbar-商品表格-插槽
目标: 使用插槽技术, 和作用域插槽技术, 给MyTable.vue组件, 自定义列标题, 自定义表格内容
- 需求: 允许用户自定义表格头和表格单元格内容
分析:
①: 把MyTable.vue里准备slot
②: 使用MyTable组件时传入具体标签
步骤:
- 提高组件==复用性和灵活性==, 把表格列标题thead部分预留
标签, 设置name属性 - 使用MyTable.vue时, 传入列标题标签
- 表格内容td部分也可以让组件使用者自定义, 也给tbody下tr内留好
标签和name属性名 - 使用插槽需要用到插槽内的obj对象上的数据, 使用作用域插槽技术
MyTable.vue - 留好具名插槽
<template>
<table class="table table-bordered table-stripped">
<!-- 表格标题区域 -->
<thead>
<tr>
<slot name="head"></slot>
</tr>
</thead>
<!-- 表格主体区域 -->
<tbody>
<tr v-for="item in list" :key="item.id">
<slot :row="item" name="body"></slot>
</tr>
</tbody>
</table>
</template>
<script>
export default {
name: "MyTable",
props: {
list: {
type: Array,
required: true,
},
},
};
</script>
<style scoped lang="less">
.my-goods-list {
.badge {
margin-right: 5px;
}
}
</style>
MyGoodsList.vue
<template>
<div>
<my-table :list="list">
<template #head>
<!-- <template slot="head"> -->
<!-- <template v-slot:head> -->
<th>#</th>
<th>商品名称</th>
<th>价格</th>
<th>标签</th>
<th>操作</th>
</template>
<template #body="{ row }">
<td>{{ row.id }}</td>
<td>{{ row.goods_name }}</td>
<td>{{ row.goods_price }}</td>
<td>{{ row.tags }}</td>
<td>
<button class="btn btn-danger btn-sm">删除</button>
</td>
</template>
</my-table>
</div>
</template>
<script>
import MyTable from "../components/MyTable.vue";
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3000";
export default {
components: {
MyTable,
},
data() {
return {
list: [], // 用来接收数据
};
},
created() {
this.getGoodsList();
},
methods: {
getGoodsList() {
axios.get("/goodsList").then(({ data }) => {
this.list = data; // 获取返回的数据
});
},
},
};
</script>
<style>
</style>
3.6 案例-tabbar-商品表格-tags微标
目标: 把单元格里的标签, tags徽章铺设下
- 需求: 标签列自定义显示
分析:
①: 插槽里传入的td单元格
②: 自定义span标签的循环展示-给予样式
效果演示:
bootstrap徽章: https://v4.bootcss.com/docs/components/badge/
MyGoodsList.vue - 插槽
class=”badge badge-warning”
>
{{ str }}
下面额外添加样式
3.7 案例-tabbar-商品表格-删除功能
目标: 点击删除对应这条数据
- 需求: 点击删除按钮删除数据
分析:
①: 删除按钮绑定点击事件
②: 作用域插槽绑定id值出来
③: 传给删除方法, 删除MyGoodsList.vue里数组里数据
效果演示
提示: id在MyTable.vue里, 但是MyGoodsList.vue里要使用, 而且在插槽位置, 使用作用域插槽已经把整个obj对象(包含id)带出来了
MyGoodsList.vue组件
<template>
<div>
<my-table :list="list">
<template #head>
<!-- <template slot="head"> -->
<!-- <template v-slot:head> -->
<th>#</th>
<th>商品名称</th>
<th>价格</th>
<th>标签</th>
<th>操作</th>
</template>
<template #body="{ row }">
<td>{{ row.id }}</td>
<td>{{ row.goods_name }}</td>
<td>{{ row.goods_price }}</td>
<!-- 循环row.tags -->
<td>
<span
class="badge badge-warning"
v-for="(item, index) in row.tags"
:key="index"
>{{ item }}</span
>
</td>
<td>
<button @click="delGoods(row.id)" class="btn btn-danger btn-sm">
删除
</button>
</td>
</template>
</my-table>
</div>
</template>
<script>
import MyTable from "../components/MyTable.vue";
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3000";
export default {
components: {
MyTable,
},
data() {
return {
list: [], // 用来接收数据
};
},
created() {
this.getGoodsList();
},
methods: {
getGoodsList() {
axios.get("/goodsList").then(({ data }) => {
this.list = data; // 获取返回的数据
});
},
delGoods(id) {
// 正常的方式
if (confirm("确定要删除该商品吗")) {
// axios.delete("/goodsList/" + id); // 正常应该调用删除接口
this.list = this.list.filter((item) => item.id !== id); // 测试开发
// this.getGoodsList();
}
},
},
};
</script>
<style>
</style>
3.8 案例-tabbar-添加tab
目标: 实现点击tab按钮, 出现输入框自动获取焦点, 失去焦点关闭input, 回车新增tag, esc清空内容
- 需求1: 点击Tab, 按钮消失, 输入框出现
- 需求2: 输入框自动聚焦
- 需求3: 失去焦点, 输入框消失, 按钮出
- 需求4: 监测input回车, 无数据拦截
- 需求5: 监测input取消, 清空数据
- 需求6: 监测input回车, 有数据添加
3.8.0 点击按钮消失, 输入框出现
MyGoodsList.vue - 标签位置添加
注意: 每个tab按钮和input都是独立变量控制, 那么直接在row身上的属性控制即可
<input
class="tag-input form-control"
style="width: 100px;"
type="text"
v-if="row.inputVisible"
/>
<button
v-else
style="display: block;"
class="btn btn-primary btn-sm add-tag"
@click="row.inputVisible = true"
>+Tag</button>
3.8.1 input自动获取焦点
main.js - 定义全局自定义指令
directives: {
focus: {
// 指令作用的标签插入元素之后 生效
inserted(el) {
el.focus(); // 聚焦
},
},
},
MyGoodsList.vue - 使用 v-focus指令
3.8.2 input失去焦点关闭input
监听input失去焦点事件, 让input消失
<input
class="tag-input form-control"
style="width: 100px"
type="text"
v-if="row.inputVisible"
v-focus
@blur="row.inputVisible = false"
@keyup.enter="enterInput($event, row)"
@keyup.esc="$event.target.value = ''"
/>
3.8.3 input回车新增tag
监听input的回车事件, 如果无数据拦截代码
<input
class="tag-input form-control"
style="width: 100px"
type="text"
v-if="row.inputVisible"
v-focus
@blur="row.inputVisible = false"
@keyup.enter="enterInput($event, row)"
@keyup.esc="$event.target.value = ''"
/>
事件处理函数
enterInput(event, row) {
if (!event.target.value) {
alert("输入内容不能为空");
return;
}
row.tags.push(event.target.value);
event.target.value = ""; // 清空原来的值
},
3.8.4 input框esc清空内容
<input
class="tag-input form-control"
style="width: 100px"
type="text"
v-if="row.inputVisible"
v-focus
@blur="row.inputVisible = false"
@keyup.enter="enterInput($event, row)"
@keyup.esc="$event.target.value = ''"
/>
MyGoodsList.vue完整代码
<template>
<div>
<my-table :list="list">
<template #head>
<!-- <template slot="head"> -->
<!-- <template v-slot:head> -->
<th>#</th>
<th>商品名称</th>
<th>价格</th>
<th>标签</th>
<th>操作</th>
</template>
<template #body="{ row }">
<td>{{ row.id }}</td>
<td>{{ row.goods_name }}</td>
<td>{{ row.goods_price }}</td>
<!-- 循环row.tags -->
<td>
<!-- 需要放入按钮和输入框 -->
<!-- 互斥 -->
<input
class="tag-input form-control"
style="width: 100px"
type="text"
v-if="row.inputVisible"
v-focus
@blur="row.inputVisible = false"
@keyup.enter="enterInput($event, row)"
@keyup.esc="$event.target.value = ''"
/>
<button
v-else
style="display: block"
class="btn btn-primary btn-sm add-tag"
@click="row.inputVisible = true"
>
+Tag
</button>
<span
class="badge badge-warning"
v-for="(item, index) in row.tags"
:key="index"
>{{ item }}</span
>
</td>
<td>
<button @click="delGoods(row.id)" class="btn btn-danger btn-sm">
删除
</button>
</td>
</template>
</my-table>
</div>
</template>
<script>
import MyTable from "../components/MyTable.vue";
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3000";
export default {
components: {
MyTable,
},
data() {
return {
list: [], // 用来接收数据
};
},
directives: {
focus: {
// 指令作用的标签插入元素之后 生效
inserted(el) {
el.focus(); // 聚焦
},
},
},
created() {
this.getGoodsList();
},
methods: {
getGoodsList() {
axios.get("/goodsList").then(({ data }) => {
this.list = data; // 获取返回的数据
});
},
delGoods(id) {
// 正常的方式
if (confirm("确定要删除该商品吗")) {
// axios.delete("/goodsList/" + id); // 正常应该调用删除接口
this.list = this.list.filter((item) => item.id !== id); // 测试开发
// this.getGoodsList();
}
},
enterInput(event, row) {
if (!event.target.value) {
alert("输入内容不能为空");
return;
}
row.tags.push(event.target.value);
event.target.value = ""; // 清空原来的值
},
},
};
</script>
<style>
</style>
4.路由的概念
路由就是一种映射关系
接口和地址的映射- 后端路由
前端路由
地址- 组件的映射关系
SPA-单页应用-多个组件
地址对应组件- 1个地址对应一个组件
的特点 hash值- #后面的值的变化不会引起页面的刷新
可以监测到hash值的变化
也有不带# 属于history模式
好处-地址简洁-比较符合编程习惯
history正常情况下,地址变化会因为页面刷新,但是后端可以处理-监听到页面请求,不响应。
- hash模式
- history模式
项目中需要场景切换
6. 使用VueRouter导入路由的使用
- 手动创建
安装vue-router
$ npm i vue-router@3.5.3
如果不知道版本,就去npmjs官网,查询包名-查出有多少个版本
- 新建单独的文件夹 router/index.js ```javascript import Vue from ‘vue’ import VueRouter from ‘vue-router’
Vue.use(VueRouter) // use会调用传入对象的install方法,并且会传入vue
export default new VueRouter({ routes: [{ path: ‘/login’, component: login }, { path: ‘/home’, component: home },{ path: ‘/article’, component: article }]
})
> main.js挂载路由
```javascript
import router from '@/router'
new Vue({
router
})
路由要展示-还需要容器
App.vue
<router-view></router-view>
// 路由切换的组件就会在这里展示
- 自动选择
创建项目的时候,选择多选模式-选上Router
7.声明式导航
- router-link可以提供声明式导航
to-属性表示要跳的地址<router-link to="/login">登录</router-link>
激活样式,可以针对激活样式做一些显示的效果
- vue-router提供了一个全局组件 router-link
- router-link实质上最终会渲染成a链接 to属性等价于提供 href属性(to无需#)
- router-link提供了声明式导航高亮的功能(自带类名)