vue第五天
一、案例-购物车
1.获取数据
(1)在reques.js文件中设置引入axios,并设置基地址
// utils/request.js
// 改造 axios 添加基地址后重新导出
import axios from 'axios'
axios.defaults.baseURL = 'https://www.escook.cn'
export default axios
(2)在api文件夹中创建cart.js文件,并且引入经过修改request.js,封装接口函数,导出供页面使用,获取购物车数据(具名导出,与其他函数进行区分)
import request from "@/utils/request.js"
export function getCar(){
return request({
url:"/api/cart"
})
}
(3)在App.vue父组件中,引入子组件CartHeader.vue和ProdItem.vue,并在页面进入时发送请求
<script>
import CartHeader from "@/components/CartHeader.vue"
import ProdItem from "@/components/ProdItem.vue"
import {getCart} from "@/api/cart.js"
export default {
components:{
ProdItem,
CarHeader,
},
created(){
getCart().then(res=>{
console.log("页面进入数据获取完毕")
console.log(res.data)
})
}
}
</script>
2.渲染商品
父组件App.vue
<template>
<div>
<CartHeader bg="#1d7bff" title="我的购物车"/>
<div class="list">
<ProdItem v-for="item in list" :key="item.id" :data="item"/>
</div>
<div class="footer">
<input type="checkbox" name="" id="">
<div class="total">合计¥1151.8</div>
<button>结算</button>
</div>
</div>
</template>
子组件ProdItem.vue
<template>
<div class="item">
<input v-model="data.goods_state" class="checkbox" type="checkbox" name="" :id="data.id"/>
<!-- label ,for data.id绑定可提高用户体验:点击到img时,复选框选中或取消 -->
<label :for="data.id">
<img :src="data.goods_img" alt="" />
</label>
<div class="info">
<div class="top">{{ data.goods_name }}</div>
<div class="bottom">
<div class="price">¥ {{ data.goods_price }}</div>
<div class="number">
<button @click="data.goods_count--">-</button>
<input type="number" v-model.number="data.goods_count" />
<button @click="data.goods_count++">+</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["data"],
};
</script>
3.单一商品选中
主要是复习了 label 标签的使用
<!-- label ,for data.id绑定可提高用户体验:点击到img时,复选框选中或取消 -->
<input v-model="data.goods_state" class="checkbox" type="checkbox" name="" :id="data.id" />
<label :for="data.id">
<img :src="data.goods_img"/>
</label>
4.单一商品数量
输入框已经绑定好,需要做修改的是加减按钮
<div class="number">
<button @click="data.goods_count--">-</button>
<input type="number" v-model.number="data.goods_count" />
<button @click="data.goods_count++">+</button>
</div>
export default {
watch: {
"data.goods_count": function (newVal) {
if (newVal < 1) {
this.data.goods_count = 1;
}
},
},
};
5.全选按钮
(1)被动 carfooter.vue
export default {
props: ['list'],
computed: {
isAll() {
return this.list.every(item=>item.goods_state)
}
}
};
(2)主动carfooter.vue
export default {
props: ['list'],
computed: {
isAll: {
get() {
return this.list.every(item=>item.goods_state)
},
set(isChecked) {
// 这里可以接收到全选的布尔值,
// 将所有商品状态改为跟全选状态一样即可
this.list.forEach(element => {
element.goods_state = isChecked
});
}
}
}
};
6.总数量和总价格
totalPrice() {
// 总价=列表中所有被勾选的商品的单价乘以数量累加起来
let res = 0
this.list.forEach(element => {
if (element.goods_state) {
res += element.goods_count * element.goods_price
}
});
return res
},
totalCount() {
let res = 0
this.list.forEach(element => {
if (element.goods_state) {
res += element.goods_count
}
});
return res
}
二、动态组件、组件缓存、声明周期扩展
1.动态组件
(1)作用:
多个组件使用同一个挂载点,并动态切换
(2)分析
①准备被切换的 - UserName.vue / UserInfo.vue 2个组件
②引入到App.vue注册
③准备变量来承载要显示的"组件名"
④设置挂载点, 使用is属性来设置要显示哪个组件
⑤点击按钮 – 修改comName变量里的"组件名"
<template>
<div>
<button @click="componentName = 'UserInfo'">个人信息</button>
<button @click="componentName = 'UserName'">账号登录</button>
<!-- vue内置标签 component 是动态组件挂载点, 会根据绑定的 is 属性显示名字对应的组件 -->
<component :is="componentName" />
</div>
</template>
<script>
import UserInfo from '@/components/UserInfo.vue'
import UserName from '@/components/UserName.vue'
export default {
data() {
return {
componentName: 'UserInfo'
}
},
components: {
UserInfo,
UserName
}
}
</script>
<style></style>
2.缓存组件-初步使用
keep-alive标签包裹动态组件挂载点
<keep-alive>
<component :is="componentName" />
</keep-alive>
3.生命周期拓展
activated – 激活时触发 deactivated – 失去激活状态触发
activated() {
console.log('缓存的组件被激活(显示)');
},
deactivated() {
console.log('缓存的组件被隐藏');
}
三、插槽使用
1.作用:
通过 slot 标签, 让组件内可以接收不同的标签结构显示
2.语法:
(1)组件内用占位
(2)使用组件时夹着的地方, 传入标签替换slot
父组件:App.vue
<template>
<div>
<!-- 员工页使用, 就要带导入员工新建员工按钮 -->
<TopBar>
<button>新增员工</button>
<button>导入员工</button>
</TopBar>
<!-- 工资页面使用需要一个报表按钮 -->
<TopBar>
<button>报表</button>
</TopBar>
</div>
</template>
<script>
import TopBar from '@/components/TopBar.vue'
export default {
components: {
TopBar
}
}
</script>
<style>
</style>
子组件:子组件.vue
<template>
<div class="topBar">
<div class="left"></div>
<div class="right">
<!-- 插槽占位标签 -->
<slot/>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
.topBar {
display: flex;
justify-content: space-between;
border: 2px solid salmon;
}
</style>
3.默认显示内容设定
<template>
<div class="topBar">
<div class="left"></div>
<div class="right">
<!-- 插槽占位标签 -->
<slot>
<!-- 如果外面没有传入, 默认显示的内容 -->
欢迎来到我的页面
</slot>
</div>
</div>
</template>
4.具名插槽
(1)作用:
一个组件内有2处以上需要外部传入标签的地方
(2)语法:
①slot使用name属性区分名字
<div class="left">
<slot name="left"/>
</div>
<div class="right">
<!-- 插槽占位标签 -->
<slot name="right">
<!-- 如果外面没有传入, 默认显示的内容 -->
欢迎来到我的页面
</slot>
</div>
②template配合v-slot:名字来分发对应标签
<TopBar>
<!-- v-slot: 可以被简化成# -->
<template #left>
一共 666 位员工
</template>
<template #right>
<button>新增员工</button>
<button>导入员工</button>
</template>
</TopBar>
<!-- 工资页面使用需要一个报表按钮 -->
<TopBar>
<template v-slot:left>
5月工资报表
</template>
<template v-slot:right>
<button>报表</button>
</template>
</TopBar>
5.作用域插槽
(1)作用:
使用插槽时, 想使用子组件内变量
(2)语法:
①子组件, 在slot上绑定属性和子组件内的值
②使用组件, 传入自定义标签, 用template和v-slot="自定义变量名"
③scope变量名自动绑定slot上所有属性和值 scope = {row: defaultObj}
子组件:
<slot :row="monthList" name="left">
{{monthList.first}} 工资报表
</slot>
父组件:
<template v-slot:left="scope">
{{scope.row.second}} 工资报表
</template>
6.作用域插槽具体使用场景
封装一个灵活的表格组件
<template>
<div>
<slotVue>
<template v-slot:left="scope">
<div>{{ scope.row.second }}月工资表</div>
</template>
<!-- v-slot:名 简写 #名 #right -->
<template v-slot:right>
<button>新增</button>
<button>报表</button>
</template>
</slotVue>
</div>
</template>
<script>
import slotVue from "./components/slot.vue";
export default {
components: {
slotVue,
},
};
</script>
7.自定义指令的使用方式
<template>
<div>
<!-- 使用自定义指令, 跟普通vue指令一样, 请千万注意,要加上 v- 前缀 -->
<input type="text">
<br>
<input type="text">
<br>
<input v-autofocus type="text">
</div>
</template>
<script>
export default {
// 局部指令注册
// directives: {
// 指令名字符串: {
// 配置对象
// 可以指定使用这个指令的元素, 在不同生命周期执行的函数
// 在这些钩子函数的形参中, 默认第一个可以获取元素本身, 第二个可以用来传参
// inserted,
// update
// }
// }
directives: {
autofocus: {
inserted(el) {
console.log(el, '自动聚焦');
el.focus()
}
}
}
}
</script>
<style>
</style>