Vue中的计算属性是什么,为什么要用计算属性,有什么好处,computed计算属性和methods方法有什么区别?
在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部this指向vm实例;④在template调用时,直接写计算属性名即可;⑤常用的是getter方法,获取数据,也可以使用set方法改变数据;⑥相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算。
效果图
实战例子:
代码块部分
<template>
<div class="main">
<div class="hand">
<label>商品名称</label>
<input type="text" placeholder="请输入查询内容" v-model="inputs" />
<p>监听购物车数量变化、金额变化、物品模糊查询、计算属性的应用</p>
</div>
<div class="table">
<table cellpadding="0" cellspacing="0">
<tr>
<th>
<input type="checkbox" v-model="allCheck" @change="allClick" />
</th>
<th>编号</th>
<th>商品图片</th>
<th>商品名称</th>
<th>商品数量</th>
<th>商品单价(元)</th>
<th>商品金额(元)</th>
</tr>
<tr v-for="(item, index) in searchData" :key="index">
<td>
<input type="checkbox" v-model="item.check" @click="checkClick" />
</td>
<td>{{ index + 1 }}</td>
<td><img :src="item.imgUrl" alt="" /></td>
<td>{{ item.name }}</td>
<td>
<div class="action">
<span @click="reduce(item)">-</span>
<span>{{ item.count }}</span>
<span @click="add(item)">+</span>
</div>
</td>
<td>{{ item.price | priceFilter(2) }}</td>
<td>{{ (item.count * item.price) | priceFilter(2) }}</td>
</tr>
</table>
<div class="hint">
<span>
{{ totalCount }}件商品总计(不含运费){{ totalPrice | priceFilter(2) }}
</span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
inputs: "",
allCheck: false,
dataInfo: [
{
name: "桃子",
count: 0,
price: 22.11,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/7468e3fe65d549ac87d6f7ea40d831a6.png",
},
{
name: "龙眼",
count: 0,
price: 9.01,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/501ba15a36b94712b4a723dcfabe9521.png",
},
{
name: "橘子",
count: 0,
price: 8.12,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/7e681c2a7bc34dd98e67d39a370a2283.png",
},
{
name: "芒果",
count: 0,
price: 6.01,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/3d0e879501ad43ae823c6d33dc7e7a89.png",
},
{
name: "提子",
count: 0,
price: 20.19,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/b99515cb80b24ebe931669cdfc77d0a2.png",
},
{
name: "蛇果",
count: 0,
price: 10.11,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/c620d20124e346fa93407c7ae9ab13b6.png",
},
{
name: "猕猴桃",
count: 0,
price: 30.11,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/28c844412cd9486b968242dcc34b27bd.png",
},
{
name: "苹果",
count: 0,
price: 10.01,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/b21b6c6ec4fd4be1a3467adf3e9fc460.png",
},
{
name: "椰子",
count: 0,
price: 17.15,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/2daaa4a37d174b7ea8d719a93f9f8130.png",
},
{
name: "哈密瓜",
count: 0,
price: 13.14,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/25b9bf8e35324f028499e2ae1f4f2b19.png",
},
{
name: "西瓜",
count: 0,
price: 8.15,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/aff0d0181c2a4841b549466df16d4174.png",
},
{
name: "梨子",
count: 0,
price: 4.19,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/012638d866af4f939efd0b35507a5053.png",
},
{
name: "火龙果",
count: 0,
price: 20.11,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/0afbb3ef68ba42d3b4097ec2871b55df.png",
},
{
name: "车厘子",
count: 0,
price: 50.1,
check: false,
imgUrl:
"https://img-blog.csdnimg.cn/9baeef4238b24b9382172be32c00221c.png",
},
],
};
},
filters: {
priceFilter: function (type, n) {
//过滤器
return "¥" + type.toFixed(n);
},
},
computed: {
totalCount: function () {
//总件数
var n = 0;
for (var i = 0; i < this.searchData.length; i++) {
if (this.searchData[i].check) {
n += this.searchData[i].count;
}
}
return n;
},
totalPrice: function () {
//总价
var n = 0;
for (var i = 0; i < this.searchData.length; i++) {
if (this.searchData[i].check) {
n += this.searchData[i].count * this.searchData[i].price;
}
}
return n;
},
searchData: function () {
//查询
if (!this.inputs) {
return this.dataInfo;
}
return this.dataInfo.filter((item) => {
return item.name.includes(this.inputs);
});
},
},
methods: {
add(item) {
//加加
item.count = item.count + 1;
},
reduce(item) {
//减减
if (item.count > 0) {
item.count = item.count - 1;
}
},
allClick() {
this.dataInfo.forEach((item) => {
item.check = this.allCheck;
});
},
checkClick() {
var n = this.dataInfo.filter((item) => {
return item.check == true;
}).length;
console.log(n, this.dataInfo.length - 1);
if (n == this.dataInfo.length - 1) {
this.allCheck = true;
} else {
this.allCheck = false;
}
},
},
};
</script>
<style scoped>
* {
padding: 0;
margin: 0;
user-select: none;
}
.hand {
display: flex;
padding: 20px 10px;
box-sizing: border-box;
border: 1px solid #c0c4cc;
border-bottom: none;
position: relative;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.hand label {
font-size: 10px;
color: #fff;
background-color: #409eff;
padding: 0 10px;
display: flex;
align-items: center;
justify-content: center;
font-family: "宋体";
height: 27px;
line-height: 27px;
}
.hand input {
font-size: 12px;
color: #666;
box-sizing: border-box;
padding: 0 8px;
line-height: 27px;
height: 27px;
border: none;
border: 1px solid #c0c4cc;
outline: none;
font-family: "宋体";
}
.hand p {
font-size: 20px;
color: #777;
font-weight: bold;
font-family: "宋体";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.table th,
td {
border-left: 1px solid #c0c4cc;
border-bottom: 1px solid #c0c4cc;
text-align: center;
font-size: 15px;
color: #666;
font-family: "宋体";
}
.table th {
padding: 25px 0;
}
.table table {
width: 100%;
border: 1px solid #c0c4cc;
border-left: none;
border-bottom: none;
}
.table input {
text-align: center;
}
.table .action span {
font-size: 14px;
color: #000;
border: 1px solid #c8c7cc;
display: inline-block;
line-height: 25px;
width: 30px;
text-align: center;
box-sizing: border-box;
}
.table .action span:nth-child(2) {
border-left: none;
border-right: none;
}
.table img {
width: 100px;
height: 100px;
}
.hint span {
font-size: 20px;
color: #222;
border: 1px solid #c0c4cc;
border-top: none;
text-align: center;
line-height: 60px;
letter-spacing: 2px;
display: block;
font-family: "宋体";
}
</style>
(2).分页功能
<template>
<div class="main">
<div class="hand">
<p>商品信息统计表(商品一共{{ rows }}件)</p>
</div>
<div class="table">
<table cellpadding="0" cellspacing="0">
<tr>
<th>商品序号</th>
<th>商品图片</th>
<th>商品名称</th>
<th>商品原价</th>
<th>商品现价</th>
</tr>
<tr v-for="(item, index) in list" :key="index">
<td>{{ (Total - 1) * page + index + 1 }}</td>
<td>
<img :src="item.product_img_url" v-if="item.product_img_url" />
<img v-else />
</td>
<td>{{ item.product_name }}</td>
<td>{{ item.product_price | priceFilter(2) }}</td>
<td>{{ item.product_uprice | priceFilter(1) }}</td>
</tr>
</table>
<div class="hint">
<div class="laypage">
<div class="prew" @click="prew()">
<span>-</span>
</div>
<div class="num">
<span
v-for="(item, index) in psges"
:key="index"
@click="click(item)"
:class="item == Total ? 'active' : ''"
>{{ item }}</span
>
</div>
<div class="last" @click="next()">
<span>+</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [], //展示数据
rows: 1, //总数据
pageTotal: 1, //总页数
Total: 1, //当前的页数
page: 8, //条数
};
},
methods: {
getList(v) {
this.Total = v || this.Total;
this.$axios({
method: "get",
url: `http://1.117.165.21:7002/home/page/${this.Total}/${this.page}`,
})
.then((res) => {
console.log(res);
this.list = res.data.data; //赋值
this.rows = res.data.rows; //总数据
this.pageTotal = res.data.pageTotal; //总页数
})
.catch((error) => {
console.log(error);
});
},
click(v) {
this.getList(v);
},
prew() {
if (this.Total > 1) {
this.Total--;
this.getList();
}
},
next() {
if (this.Total < this.pageTotal) {
this.Total++;
this.getList();
}
},
},
mounted() {
this.getList();
},
filters: {
priceFilter(type, n) {
//保留两位小数
if (typeof type == "undefined") {
return type;
} else {
return "¥" + type.toFixed(n);
}
},
},
computed: {
psges() {
var pageTotal = this.pageTotal;
var Total = this.Total;
if (Total <= 5) {
return [1, 2, 3, 4, 5, 6, 7, 8, 9, "...", pageTotal];
} else if (Total >= pageTotal - 5) {
return [
1,
"...",
pageTotal - 8,
pageTotal - 7,
pageTotal - 6,
pageTotal - 5,
pageTotal - 4,
pageTotal - 3,
pageTotal - 2,
pageTotal - 1,
pageTotal,
];
} else {
return [
1,
"...",
Total - 3,
Total - 2,
Total - 1,
Total,
Total + 1,
Total + 2,
Total + 3,
"...",
pageTotal,
];
}
},
},
};
</script>
<style scoped>
* {
padding: 0;
margin: 0;
user-select: none;
font-size: 0;
}
.main {
width: 80%;
margin: 0 auto;
}
.hand {
padding: 10px;
box-sizing: border-box;
border: 1px solid #c0c4cc;
border-bottom: none;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.hand p {
font-size: 20px;
color: #777;
font-weight: bold;
font-family: "宋体";
line-height: 40px;
}
.table th,
td {
border-left: 1px solid #c0c4cc;
border-bottom: 1px solid #c0c4cc;
text-align: center;
font-size: 15px;
color: #666;
font-family: "宋体";
}
.table th {
padding: 20px 0;
}
.table img {
width: 60px;
height: 60px;
padding: 10px 0;
}
.table table {
width: 100%;
border: 1px solid #c0c4cc;
border-left: none;
border-bottom: none;
}
.table input {
text-align: center;
}
.table .action span {
font-size: 14px;
color: #000;
border: 1px solid #c8c7cc;
display: inline-block;
line-height: 25px;
width: 30px;
text-align: center;
box-sizing: border-box;
}
.table .action span:nth-child(2) {
border-left: none;
border-right: none;
}
.hint {
border: 1px solid #c0c4cc;
border-top: none;
padding: 20px;
box-sizing: border-box;
}
.hint .laypage {
margin: 0 auto;
display: flex;
width: 35%;
}
.hint .laypage .prew span {
padding: 0 15px;
}
.hint .laypage .last span {
padding: 0 15px;
}
.hint .laypage .num {
display: flex;
flex: 1;
}
.hint span {
font-size: 20px;
color: #222;
border: 1px solid #c0c4cc;
text-align: center;
line-height: 40px;
letter-spacing: 2px;
display: block;
font-family: "宋体";
flex: 1;
}
.hint span.active {
background-color: aqua;
}
</style>