乐意购项目前端开发 #7

一、购物车

本地购物车

创建cartStore.js文件

创建cartStore.js文件, 将购物车列表数据存在pinia中

import { ref, computed } from "vue";
import { defineStore } from "pinia";
import { useUserStore } from "./user";
import {insertCartAPI,findNewCartListAPI,delCartAPI,
} from "@/api/cart/index";export const useCartStore = defineStore("cart",() => {const userStore = useUserStore();const isLogin = computed(() => userStore.userInfo.token);console.log("已经执行登录验证");//1.定义state - cartListconst cartList = ref([]);// 2. 定义action - addCartconst addCart = async (goods) => {console.log(goods);const { id, count } = goods;if (isLogin.value) {// 登录之后的加入购车逻辑await insertCartAPI({ id, count });const res = await findNewCartListAPI();cartList.value = res.data;console.log("cartList已经赋值");} else {console.log("cartList没有赋值");// 添加购物车操作// 已添加过 - count + 1// 没有添加过 - 直接push// 思路:通过匹配传递过来的商品对象中的id能不能在cartList中找到,找到了就是添加过const item = cartList.value.find((item) => goods.id === item.goodsId);console.log("item=" + item);if (item) {// 找到了item.buyCount++;} else {console.log("这里运行了");// 没找到cartList.value.push(goods);}}};// 删除购物车const delCart = async (goodsId) => {if (isLogin.value) {// 调用接口实现接口购物车中的删除功能await delCartAPI([goodsId]);const res = await findNewCartListAPI();cartList.value = res.data;} else {console.log("cartdel操作已执行");// 思路:// 1. 找到要删除项的下标值 - splice// 2. 使用数组的过滤方法 - filterconst idx = cartList.value.findIndex((item) => goodsId === item.goodsId);cartList.value.splice(idx, 1);}};//更新购物车const updateNewList = async () => {const res = await findNewCartListAPI();cartList.value = res.data;console.log("已更新购物车")};//清除购物车const clearCart = () => {cartList.value = [];};// 计算属性// 1. 总的数量 所有项的count之和const allCount = computed(() =>cartList.value.reduce((a, c) => a + c.buyCount, 0));// 2. 总价 所有项的count*price之和const allPrice = computed(() =>cartList.value.reduce((a, c) => a + c.buyCount * c.goodsPrice, 0));// 单选功能const singleCheck = (goodsId, selected) => {// 通过id找到要修改的那一项 然后把它的selected修改为传过来的selectedconst item = cartList.value.find((item) => item.goodsId === goodsId);item.selected = selected;};// 全选功能actionconst allCheck = (selected) => {// 把cartList中的每一项的selected都设置为当前的全选框状态cartList.value.forEach((item) => (item.selected = selected));};// 是否全选计算属性const isAll = computed(() => cartList.value.every((item) => item.selected));// 3. 已选择数量const selectedCount = computed(() =>cartList.value.filter((item) => item.selected).reduce((a, c) => a + c.buyCount, 0));// 4. 已选择商品价钱合计const selectedPrice = computed(() =>cartList.value.filter((item) => item.selected).reduce((a, c) => a + c.buyCount * c.goodsPrice, 0));return {updateNewList,clearCart,selectedPrice,selectedCount,isAll,allCheck,singleCheck,cartList,allCount,allPrice,addCart,delCart,};},{persist: true,}
);
 封装接口

创建文件

import http from '@/utils/http'// 加入购物车
export function insertCartAPI ({ id,count}) {return http({url: '/cart',method: 'POST',data:{"goodsId":id,"buyCount":count},})
}//获取最新的购物车列表
export function findNewCartListAPI () {return http({url: '/cart',method: 'GET',})
}
//获取最新的购物车列表
export function delCartAPI (ids) {return http({url: '/cart',method: 'DELETE',data:{"ids":ids}})
}

前往商品详情页面 Detail\index.vue绑定事件和事件逻辑

<script setup>
import { getDetail } from "@/api/goods/index";
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { useCartStore } from '@/store/cartStore';const cartStore = useCartStore()
const route = useRoute();
const goods = ref({});
const category = ref({});
const seller = ref({});const getGoods = async () => {const res = await getDetail(route.params.id);goods.value = res.data.good;category.value = res.data.category;seller.value = res.data.seller;console.log(res.data.pictureList)imageList.value = res.data.pictureList
};
//count
const count = ref(1)
const countChange = (count) => {console.log(count);
}
//添加购物车
const addCart = () => {//console.log(goods)cartStore.addCart({id: goods.value.id,name: goods.value.goodsName,picture: goods.value.picture1,price: goods.value.price,count: count.value,// attrsText: skuObj.specsText,selected: true})}onMounted(() => {getGoods();
});
console.log(imageList);
</script><template><!-- 数据组件 --><el-input-number :min="1" v-model="count" @change="countChange" /><!-- 按钮组件 --><div><el-button size="large" class="btn" @click="addCart">加入购物车</el-button></div>
</template>

头部购物车

1.创建文件

views/Layout/compopnent/HeaderCart.vue

<script setup>
import { useCartStore } from "@/store/cartStore";
const cartStore = useCartStore();
</script><template><div class="cart"><a class="curr" href="javascript:;"><i class="iconfont icon-cart"></i><em>{{ cartStore.allCount }}</em></a><div class="layer"><div class="list"><div class="item" v-for="i in cartStore.cartList" :key="i.id"><RouterLink to=""><img :src="i.picture1" alt="" /><div class="center"><p class="name ellipsis-2">{{ i.goodsName }}</p><!-- <p class="attr ellipsis">{{ i.attrsText }}</p> --></div><div class="right"><p class="price">&yen;{{ i.goodsPrice }}</p><p class="count">x{{ i.buyCount }}</p></div></RouterLink><i class="iconfont icon-close-new" @click="cartStore.delCart(i.id)"></i></div></div><div class="foot"><div class="total"><p>共 {{ cartStore.allCount }} 件商品</p><p>&yen; {{ cartStore.allPrice }}</p></div><el-button size="large" type="primary" @click="$router.push('/cartlist')">去购物车结算</el-button></div></div></div>
</template><style scoped lang="scss">
.cart {width: 50px;position: relative;z-index: 600;.curr {height: 32px;line-height: 32px;text-align: center;position: relative;display: block;.icon-cart {font-size: 22px;}em {font-style: normal;position: absolute;right: 0;top: 0;padding: 1px 6px;line-height: 1;background: $helpColor;color: #fff;font-size: 12px;border-radius: 10px;font-family: Arial;}}&:hover {.layer {opacity: 1;transform: none;}}.layer {opacity: 0;transition: all 0.4s 0.2s;transform: translateY(-200px) scale(1, 0);width: 400px;height: 400px;position: absolute;top: 50px;right: 0;box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);background: #fff;border-radius: 4px;padding-top: 10px;&::before {content: "";position: absolute;right: 14px;top: -10px;width: 20px;height: 20px;background: #fff;transform: scale(0.6, 1) rotate(45deg);box-shadow: -3px -3px 5px rgba(0, 0, 0, 0.1);}.foot {position: absolute;left: 0;bottom: 0;height: 70px;width: 380px;padding: 10px;display: flex;justify-content: space-between;background: #f8f8f8;align-items: center;.total {padding-left: 10px;color: #999;p {&:last-child {font-size: 18px;color: $priceColor;}}}}}.list {height: 310px;overflow: auto;padding: 0 10px;&::-webkit-scrollbar {width: 10px;height: 10px;}&::-webkit-scrollbar-track {background: #f8f8f8;border-radius: 2px;}&::-webkit-scrollbar-thumb {background: #eee;border-radius: 10px;}&::-webkit-scrollbar-thumb:hover {background: #ccc;}.item {border-bottom: 1px solid #f5f5f5;padding: 10px 0;position: relative;i {position: absolute;bottom: 38px;right: 0;opacity: 0;color: #666;transition: all 0.5s;}&:hover {i {opacity: 1;cursor: pointer;}}a {display: flex;align-items: center;img {height: 80px;width: 80px;}.center {padding: 0 10px;width: 200px;.name {font-size: 16px;}.attr {color: #999;padding-top: 5px;}}.right {width: 100px;padding-right: 20px;text-align: center;.price {font-size: 16px;color: $priceColor;}.count {color: #999;margin-top: 5px;font-size: 16px;}}}}}
}
</style>
2.修改LayoutHeader.vue

在views/Layout/compopnent/LayouHeader.vue中注册和使用HeaderCart组件

<script setup>import HeaderCart from './HeaderCart.vue'
</script>
<template><!-- 头部购物车 --><HeaderCart></HeaderCart>
</template>

购物车列表页面

创建文件

<script setup>
import { useCartStore } from "@/store/cartStore";
const cartStore = useCartStore();
// 单选回调
const singleCheck = (i, selected) => {console.log(i, selected);// store cartList 数组 无法知道要修改谁的选中状态?// 除了selected补充一个用来筛选的参数 - skuIdcartStore.singleCheck(i.goodsId, selected);
};
// 全选
const allCheck = (selected) => {cartStore.allCheck(selected)
}
</script><template><div class="lyg-cart-page"><div class="container m-top-20"><div class="cart"><table ><thead><tr><th width="120"><el-checkbox :model-value="cartStore.isAll" @change="allCheck" /></th><th width="400">商品信息</th><th width="220">单价</th><th width="180">数量</th><th width="180">小计</th><th width="140">操作</th></tr></thead><!-- 商品列表 --><tbody ><tr v-for="i in cartStore.cartList" :key="i.id" ><td ><!-- 单选框 --><el-checkbox:model-value="i.selected"@change="(selected) => singleCheck(i, selected)"/></td><td><div class="goods"><RouterLink to="/"><img :src="i.goodsPicture" alt=""/></RouterLink><div><p class="name ellipsis">{{ i.goodsName }}</p></div></div></td><td class="tc"><p>&yen;{{ i.goodsPrice }}</p></td><td class="tc"><el-input-number :min="0" v-model="i.buyCount" /></td><td class="tc"><p class="f16 red">&yen;{{ (i.goodsPrice * i.buyCount).toFixed(2) }}</p></td><td class="tc"><p><el-popconfirmtitle="确认删除吗?"confirm-button-text="确认"cancel-button-text="取消"@confirm="cartStore.delCart(i.id)"><template #reference><a href="javascript:;">删除</a></template></el-popconfirm></p></td></tr><tr v-if="cartStore.cartList.length === 0"><td colspan="6"><div class="cart-none"><el-empty description="购物车列表为空"><el-button type="primary" @click="$router.push('/category/hot')">随便逛逛</el-button></el-empty></div></td></tr></tbody></table></div><!-- 操作栏 --><div class="action"><div class="batch">共 {{ cartStore.allCount }} 件商品,已选择 {{ cartStore.selectedCount }} 件,商品合计:<span class="red">¥ {{ cartStore.selectedPrice.toFixed(2) }} </span></div><div class="total"><el-button size="large" type="primary" @click="$router.push('/checkout')">下单结算</el-button></div></div></div></div>
</template><style scoped lang="scss">
.lyg-cart-page {margin-top: 20px;.cart {background: #fff;color: #666;table {border-spacing: 0;border-collapse: collapse;line-height: 24px;th,td {padding: 10px;border-bottom: 1px solid #f5f5f5;&:first-child {text-align: left;padding-left: 30px;color: #999;}}th {font-size: 16px;font-weight: normal;line-height: 50px;}}}.cart-none {text-align: center;padding: 120px 0;background: #fff;p {color: #999;padding: 20px 0;}}.tc {text-align: center;a {color: $lygColor;}.lyg-numbox {margin: 0 auto;width: 120px;}}.red {color: $priceColor;}.green {color: $lygColor;}.f16 {font-size: 16px;}.goods {display: flex;align-items: center;img {width: 100px;height: 100px;}> div {width: 280px;font-size: 16px;padding-left: 10px;.attr {font-size: 14px;color: #999;}}}.action {display: flex;background: #fff;margin-top: 20px;height: 80px;align-items: center;font-size: 16px;justify-content: space-between;padding: 0 30px;.lyg-checkbox {color: #999;}.batch {a {margin-left: 20px;}}.red {font-size: 18px;margin-right: 20px;font-weight: bold;}}.tit {color: #666;font-size: 16px;font-weight: normal;line-height: 50px;}
}
</style>

二、订单信息确认页面

创建文件

创建 views/Checkout/index.vue 文件

编写代码

<script setup>
import { ref, onMounted } from "vue";
import { useCartStore } from "@/store/cartStore";
import { getCheckInfoAPI, createOrderAPI } from "@/api/order/index";
import { useRouter } from "vue-router";
const cartStore = useCartStore();
const router = useRouter();console.log(cartStore);const checkInfo = ref({}); // 订单对象
const curAddress = ref({}); // 地址对象
const time = ref({}); // 时间
const Time = new Date();
time.value = Time.getTime();
//控制弹窗打开
const showDialog = ref(false);const getCheckInfo = async () => {const res = await getCheckInfoAPI();checkInfo.value = res.data;console.log("data数据");console.log(checkInfo);//适配默认地址//从地址列表中筛选出来 isDefault === 0 那一项const item = checkInfo.value.address.find((item) => item.isDefault === 0);console.log("cauraddress数据");curAddress.value = item;console.log(curAddress);
};
//切换地址
const activeAddress = ref({});const switchAddres = (item) => {console.log("switchAddres运行");activeAddress.value = item;
};
//覆盖地址
const confirm = () => {curAddress.value = activeAddress.value;showDialog.value = false;
};// 创建订单
const createOrder = async () => {const res = await createOrderAPI({// deliveryTimeType: 1,// payType: 1,// payChannel: 1,// buyerMessage: "",// goods: checkInfo.value.goods.map((item) => {//   return {//     goodId: item.goodsId,//     buyCount: item.buyCount,//   };// }),// addressId: curAddress.value.id,// goodsIds: cartStore.cartList.filter((item) => item.selected).goodsId,// orderid: time.getTime(),goods: cartStore.cartList.filter((item) => item.selected).map((item) => {return {id: item.id,goodsId: item.goodsId,buyCount: item.buyCount,goodsPrice: (item.goodsPrice * item.buyCount).toFixed(2),};}),addressId: curAddress.value.id,amount: cartStore.selectedPrice,orderId: time.value,});console.log("已经运行到这");const orderId = time.value;console.log(orderId);console.log(orderId);cartStore.updateNewList();router.push({path: "/pay",query: {id: orderId,},});
};onMounted(() => {getCheckInfo();
});
</script><template><div class="lyg-pay-checkout-page"><div class="container"><div class="wrapper"><!-- 收货地址 --><h3 class="box-title">收货地址</h3><div class="box-body"><div class="address"><div class="text"><div class="none" v-if="!curAddress">您需要先添加收货地址才可提交订单。</div><ul v-else><li><span>收<i />货<i />人:</span>{{ curAddress.userName }}</li><li><span>联系方式:</span>{{ curAddress.phone }}</li><li><span>收货地址:</span>{{ curAddress.address }}</li></ul></div><div class="action"><el-button size="large" @click="showDialog = true">切换地址</el-button><el-button size="large">添加地址</el-button></div></div></div><!-- 商品信息 --><h3 class="box-title">商品信息</h3><div class="box-body"><table class="goods"><thead><tr><th width="520">商品信息</th><th width="170">单价</th><th width="170">数量</th><th width="170">小计</th><th width="170">实付</th></tr></thead><tbody><trv-for="i in cartStore.cartList.filter((item) => item.selected)":key="i.id"><td><a href="javascript:;" class="info"><img :src="i.picture" alt="" /><div class="right"><p>{{ i.goodsName }}</p><!-- <p>{{ i.attrsText }}</p> --></div></a></td><td>&yen;{{ i.goodsPrice }}</td><td>{{ i.buyCount }}</td><td>&yen;{{ (i.goodsPrice * i.buyCount).toFixed(2) }}</td><td>&yen;{{ (i.goodsPrice * i.buyCount).toFixed(2) }}</td></tr></tbody></table></div><!-- 配送时间 --><!-- <h3 class="box-title">配送时间</h3><div class="box-body"><a class="my-btn active" href="javascript:;">不限送货时间:周一至周日</a><a class="my-btn" href="javascript:;">工作日送货:周一至周五</a><a class="my-btn" href="javascript:;">双休日、假日送货:周六至周日</a></div> --><!-- 支付方式 --><!-- <h3 class="box-title">支付方式</h3><div class="box-body"><a class="my-btn active" href="javascript:;">在线支付</a><a class="my-btn" href="javascript:;">货到付款</a><span style="color: #999">货到付款需付5元手续费</span></div> --><!-- 金额明细 --><h3 class="box-title">金额明细</h3><div class="box-body"><div class="total"><dl><dt>商品件数:</dt><dd>{{ cartStore.selectedCount }} 件</dd></dl><dl><dt>商品总价:</dt><dd>¥{{ cartStore.selectedPrice.toFixed(2) }}</dd></dl><!-- <dl><dt>运<i></i>费:</dt><dd>¥{{ checkInfo.summary?.postFee.toFixed(2) }}</dd></dl> --><dl><dt>应付总额:</dt><dd class="price">{{ cartStore.selectedPrice.toFixed(2) }}</dd></dl></div></div><!-- 提交订单 --><div class="submit"><el-button @click="createOrder" type="primary" size="large">提交订单</el-button></div></div></div></div><!-- 切换地址 --><el-dialog v-model="showDialog" title="切换收货地址" width="30%" center><div class="addressWrapper"><divclass="text item":class="{ active: activeAddress.id === item.id }"@click="switchAddres(item)"v-for="item in checkInfo.address":key="item.id"><ul><li><span>收<i />货<i />人:</span>{{ item.userName }}</li><li><span>联系方式:</span>{{ item.phone }}</li><li><span>收货地址:</span>{{ item.address }}</li></ul></div></div><template #footer><span class="dialog-footer"><el-button @click="showDialog = flase">取消</el-button><el-button type="primary" @click="confirm">确定</el-button></span></template></el-dialog><!-- 添加地址 -->
</template><style scoped lang="scss">
.lyg-pay-checkout-page {margin-top: 20px;.wrapper {background: #fff;padding: 0 20px;.box-title {font-size: 16px;font-weight: normal;padding-left: 10px;line-height: 70px;border-bottom: 1px solid #f5f5f5;}.box-body {padding: 20px 0;}}
}.address {border: 1px solid #f5f5f5;display: flex;align-items: center;.text {flex: 1;min-height: 90px;display: flex;align-items: center;.none {line-height: 90px;color: #999;text-align: center;width: 100%;}> ul {flex: 1;padding: 20px;li {line-height: 30px;span {color: #999;margin-right: 5px;> i {width: 0.5em;display: inline-block;}}}}> a {color: $lygColor;width: 160px;text-align: center;height: 90px;line-height: 90px;border-right: 1px solid #f5f5f5;}}.action {width: 420px;text-align: center;.btn {width: 140px;height: 46px;line-height: 44px;font-size: 14px;&:first-child {margin-right: 10px;}}}
}.goods {width: 100%;border-collapse: collapse;border-spacing: 0;.info {display: flex;text-align: left;img {width: 70px;height: 70px;margin-right: 20px;}.right {line-height: 24px;p {&:last-child {color: #999;}}}}tr {th {background: #f5f5f5;font-weight: normal;}td,th {text-align: center;padding: 20px;border-bottom: 1px solid #f5f5f5;&:first-child {border-left: 1px solid #f5f5f5;}&:last-child {border-right: 1px solid #f5f5f5;}}}
}.my-btn {width: 228px;height: 50px;border: 1px solid #e4e4e4;text-align: center;line-height: 48px;margin-right: 25px;color: #666666;display: inline-block;&.active,&:hover {border-color: $lygColor;}
}.total {dl {display: flex;justify-content: flex-end;line-height: 50px;dt {i {display: inline-block;width: 2em;}}dd {width: 240px;text-align: right;padding-right: 70px;&.price {font-size: 20px;color: $priceColor;}}}
}.submit {text-align: right;padding: 60px;border-top: 1px solid #f5f5f5;
}.addressWrapper {max-height: 500px;overflow-y: auto;
}.text {flex: 1;min-height: 90px;display: flex;align-items: center;&.item {border: 1px solid #f5f5f5;margin-bottom: 10px;cursor: pointer;&.active,&:hover {border-color: $lygColor;background: lighten($lygColor, 50%);}> ul {padding: 10px;font-size: 14px;line-height: 30px;}}
}
</style>

封装接口

代码模版

import http from '@/utils/http'export function getCheckInfoAPI () {return http({url: '/order',method: 'GET',})
}
export function createOrderAPI (data) {return http({url: '/order',method: 'POST',data})
}export function getOrderAPI (id) {return http({url: `/order/${id}`,method: 'GET',})
}

配置路由

routes: [{path: '/',component: Layout,children: [...{path: "checkout",component: Checkout}]}
]

生成订单

调用接口生成订单id, 并且携带id跳转到支付页

调用更新购物车列表接口,更新购物车状态

// 创建订单
const createOrder = async () => {const res = await createOrderAPI({goods: cartStore.cartList.filter((item) => item.selected).map((item) => {return {id: item.id,goodsId: item.goodsId,buyCount: item.buyCount,goodsPrice: (item.goodsPrice * item.buyCount).toFixed(2),};}),addressId: curAddress.value.id,amount: cartStore.selectedPrice,orderId: time.value,});console.log("已经运行到这");const orderId = time.value;console.log(orderId);console.log(orderId);cartStore.updateNewList();router.push({path: "/pay",query: {id: orderId,},});
};

支付页面组件

创建文件 views/Pay/index.vue

编写代码

<script setup>
import { ref, onMounted } from 'vue'
import { getOrderAPI } from '@/api/order/index'
import { useRoute } from 'vue-router';
import { useCountDown } from '@/composables/useCountDown'
const { formatTime, start } = useCountDown()const route = useRoute()
const payInfo = ref({})
console.log(route.query.id)const getPayInfo = async () => {console.log("已经运行")console.log(route.query.id)const res = await getOrderAPI(route.query.id)payInfo.value = res.datastart(res.data.countdown)
}
onMounted(() => { getPayInfo() })
</script><template><div class="lyg-pay-page"><div class="container"><!-- 付款信息 --><div class="pay-info"><span class="icon iconfont icon-queren2"></span><div class="tip"><p>订单提交成功!请尽快完成支付。</p><p>支付还剩 <span>{{ formatTime }}</span>, 超时后将取消订单</p></div><div class="amount"><span>应付总额:</span><span>¥{{ payInfo.amount?.toFixed(2) }}</span></div></div><!-- 付款方式 --><div class="pay-type"><p class="head">选择以下支付方式付款</p><div class="item"><p>支付平台</p><a class="btn wx" href="javascript:;"></a><a class="btn alipay" :href="payUrl"></a></div><div class="item"><p>支付方式</p><a class="btn" href="javascript:;">招商银行</a><a class="btn" href="javascript:;">工商银行</a><a class="btn" href="javascript:;">建设银行</a><a class="btn" href="javascript:;">农业银行</a><a class="btn" href="javascript:;">交通银行</a></div></div></div></div>
</template><style scoped lang="scss">
.lyg-pay-page {margin-top: 20px;
}.pay-info {background: #fff;display: flex;align-items: center;height: 240px;padding: 0 80px;.icon {font-size: 80px;color: #1dc779;}.tip {padding-left: 10px;flex: 1;p {&:first-child {font-size: 20px;margin-bottom: 5px;}&:last-child {color: #999;font-size: 16px;}}}.amount {span {&:first-child {font-size: 16px;color: #999;}&:last-child {color: $priceColor;font-size: 20px;}}}
}.pay-type {margin-top: 20px;background-color: #fff;padding-bottom: 70px;p {line-height: 70px;height: 70px;padding-left: 30px;font-size: 16px;&.head {border-bottom: 1px solid #f5f5f5;}}.btn {width: 150px;height: 50px;border: 1px solid #e4e4e4;text-align: center;line-height: 48px;margin-left: 30px;color: #666666;display: inline-block;&.active,&:hover {border-color: $lygColor;}&.alipay {background: url(https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/7b6b02396368c9314528c0bbd85a2e06.png) no-repeat center / contain;}&.wx {background: url(https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/c66f98cff8649bd5ba722c2e8067c6ca.jpg) no-repeat center / contain;}}
}
</style>
倒计时组件

创建文件

// 封装倒计时函数
import { ref,computed, onUnmounted } from "vue"
import dayjs from "dayjs"export const useCountDown =()=>{// 响应式数据const time = ref(0)let timer = null// 格式化事件为xx分xx秒const formatTime = computed(()=>dayjs.unix(time.value).format('mm分ss秒'))// 开启倒计时的函数const start =(currentTime)=>{// 开启倒计时的逻辑time.value = currentTimetimer = setInterval(() => {time.value--}, 1000);}// 组件销毁清除定时器onUnmounted(() => {timer && clearInterval(timer)})return {formatTime,start}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/668447.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch使用

前言 系统环境&#xff1a;win10 使用Anaconda&#xff0c;Anaconda的安装自行百度。 conda 23.7.4 目录 前言 创建虚拟环境 1、查看当前有哪些虚拟环境 2、创建虚拟环境pytorch 3、激活及关闭pytorch虚拟环境 4、删除pytorch虚拟环境 使用yolov5测试 1、切换至yolo…

idea 快捷键ctrl+shift+f失效的解决方案

文章目录 搜狗输入法快捷键冲突微软输入法快捷键冲突 idea的快捷键ctrlshiftf按了没反应&#xff0c;理论上是快捷键冲突了&#xff0c;检查搜狗输入法和微软输入法快捷键。 搜狗输入法快捷键冲突 不需要简繁切换的快捷键&#xff0c;可以关闭它&#xff0c;或修改快捷键。 微…

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案 大家好 我是寸铁&#x1f44a; 总结了一篇Error: only one service expected goctl一键转换生成rpc服务错误解决方案的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 问题背景 今天寸铁在…

IT工单治理野史:由每周最高150+治理到20+ | 京东物流技术团队

背景 相信不少人都值过班当过小秘吧&#xff0c;每天都要在线排查与解答各种各样来自IT或"单聊"的问题&#xff0c;同时还要针对每个问题进行"复盘"分析&#xff0c;在完善系统、提高体验的同时挖掘出其中的雷点&#xff0c;防止某一天突然"爆炸&quo…

飞天使-k8s知识点12-kubernetes散装知识点1-架构有状态

文章目录 k8s架构图有状态和无状态服务 资源和对象对象规约和状态 资源的对象-资源的分类 k8s架构图 有状态和无状态服务 区分有状态和无状态服务有利于维护yaml文件 因为配置不同资源和对象 命令行yaml来定义对象对象规约和状态 规约 spec 描述对象的期望状态状态 status 对…

机器学习基础、数学统计学概念、模型基础技术名词及相关代码个人举例

1.机器学习基础 &#xff08;1&#xff09;机器学习概述 机器学习是一种人工智能&#xff08;AI&#xff09;的分支&#xff0c;通过使用统计学和计算机科学的技术&#xff0c;使计算机能够从数据中学习并自动改进性能&#xff0c;而无需进行明确的编程。它涉及构建和训练机器…

【Spring】Spring 对 Ioc 的实现

一、Ioc 控制反转 控制反转是一种思想 控制反转是为了降低程序耦合度&#xff0c;提高程序扩展力&#xff0c;达到 OCP 原则&#xff0c;达到 DIP 原则 控制反转&#xff0c;反转的是什么&#xff1f; 将对象的创建权利交出去&#xff0c;交给第三方容器负责 将对象和对象之…

Angular BaseView抽离页面公用属性

前言 如果有一系列的页面布局很类似&#xff0c;为了节省时间&#xff0c;我们可以把这些类似的页面所通用的属性和方法抽离成一个BaseView&#xff0c;让其它页面继承该基础页面&#xff0c;同时将一些经常改变的属性和差异的属性写到配置文件里。例如树容器初始时是否展开、…

什么是前端工程化,请举例说明

前端工程化 前端工程化的定义为什么需要前端工程化前端工程化的核心概念 模块化开发&#xff1a;组件化开发&#xff1a;规范化开发&#xff1a;自动化开发&#xff1a;持续集成 前端工程化的主要工具前端工程化的应用总结&#xff1a; 前端工程化 前端工程化的定义 前端工程…

从资深用户角度谈三款出色数据可视化工具

作为一名数据可视化领域的老用户&#xff0c;我接触过众多数据可视化产品&#xff0c;其中不乏佼佼者。今天&#xff0c;我想为大家介绍三款在我心目中颇具特色的数据可视化产品&#xff0c;它们分别是山海鲸可视化、Tableau和Power BI。 首先&#xff0c;让我们来谈谈山海鲸可…

STM32单片机的基本原理与应用(六)

串口测试实验 基本原理 在串口实验中&#xff0c;是通过mini_USB线搭建终端与电脑端&#xff08;也可称终端&#xff0c;为做区分称电脑端&#xff09;的“桥梁”&#xff0c;电脑端的串口调试助手通过mini_USB线向终端发送信息&#xff0c;由CH340芯片将USB接口进行转换&…

机器学习中常用的性能度量—— ROC 和 AUC

什么是泛化能力&#xff1f; 通常我们用泛化能力来评判一个模型的好坏&#xff0c;通俗的说&#xff0c;泛化能力是指一个机器学期算法对新样本&#xff08;即模型没有见过的样本&#xff09;的举一反三的能力&#xff0c;也就是学以致用的能力。 举个例子&#xff0c;高三的…

vulhub中Apache APISIX Dashboard API权限绕过导致RCE(CVE-2021-45232)

Apache APISIX是一个动态、实时、高性能API网关&#xff0c;而Apache APISIX Dashboard是一个配套的前端面板。 Apache APISIX Dashboard 2.10.1版本前存在两个API/apisix/admin/migrate/export和/apisix/admin/migrate/import&#xff0c;他们没有经过droplet框架的权限验证&…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 2月5日,星期一

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年2月5日 星期一 农历腊月廿六 1、 证监会&#xff1a;依法严厉打击操纵市场、恶意做空、内幕交易等重大违法行为。 2、 夜间高铁开行&#xff01;多地火车站候车室开启通宵服务。 3、 气象台&#xff1a;5日晚至7日湘中以…

Prometheus部署监控报警

在容器环境中配置安装Prometheus部署企业微信容器报警Grafana展示 下载Prometheus &#xff08;监控Server端&#xff09; [rootPrometheus-Grafana prometheus]# mkdir /prometheus [rootPrometheus-Grafana prometheus]# docker run -d --name test -P prom/prometheus [ro…

数据与广告系列三十七:广告,商业化的高雅,中间商赚差价的无奈

作者黄崇远 『数据巢』 全文8872字 题图ssyer.com “ 商业化广告&#xff0c;看着其技术复杂又富有挑战性&#xff0c;业务覆盖行业的方方面面又似乎不可或缺&#xff0c;但究其本质&#xff0c;依然是中间商赚差价的生意而已&#xff0c;但细究其背后的深层原因&#xff0c;却…

深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之行存(一)

在当今的大数据时代&#xff0c;高效的数据检索和分析能力已成为许多应用程序的核心需求。Elasticsearch&#xff0c;作为一款强大的分布式搜索和分析引擎&#xff0c;正是为了满足这些需求而诞生的。它之所以能够在海量数据中实现毫秒级的搜索响应&#xff0c;以及灵活的数据分…

笔记本电脑的WIFI模块,突然不显示了,网络也连接不上

问题复现&#xff1a; 早上&#xff0c;在更新完笔记本电脑的系统之后&#xff0c;连网之后&#xff0c;网络突然直接断开&#xff0c;一查看&#xff0c;WiFi模块居然不见了&#xff0c;开机重启也是如此&#xff0c;这种情况常常出现在更新系统之后&#xff0c;WiFi模块驱动就…

RK3399平台开发系列讲解(内存篇)进程内存详解

🚀返回专栏总目录 文章目录 一、虚拟地址映射的物理内存1.1、物理内存1.2、虚拟内存1.2.1、用户态:低特权运行程序1.2.2、内核态:运行的程序需要访问操作系统内核数据二、PageCache三、指标查询命令沉淀、分享、成长,让自己和他人都能有所收获!😄 📢进程消耗的内存包…

docker proxy 【docker 代理】

第一种 创建代理配置文件 mkdir -p /etc/systemd/system/docker.service.d/ cat <<EOF > /etc/systemd/system/docker.service.d/http-proxy.conf Environment"HTTP_PROXYhttp://192.168.21.101:7890" Environment"HTTPS_PROXYhttp://192.168.21.1…