- 背景
囫囵吞枣的看了一遍vue,做这个理解一下很浅显的知识(没有经验,有点乱七八糟),算是第一版,以后每进步一些能改的话就改一点。 - 结果图(css还是不熟练)
- - 代码
四个文件:
App.vue
<template>
<div>
<hr>
<h3>购物清单</h3>
<ul class='item-desc'>
<li>
<input type='checkbox' :checked='checkedAll' @change='changeChecked'>全选
</li>
<li
v-for='item,index in productItems'
:key='item'
>{{ item }}</li>
</ul>
<ul>
<li
is='TodoList'
v-for='product in products'
:product='product'
:key='product.id'
@delete='deleteProduct($event)'
></li>
</ul>
<ul class='operate-item'>
<li><input type='button' value='删除所选商品' @click='deleteCheckedProducts'></li>
<li><input type='button' value='继续购物' @click='continueBuy'></li>
<li><p><span>{{ numAll }}</span> 件商品总计(不含运费):<span>{{ monkeyIcon }}{{ allPrice }}</span></p></li>
<li><input class='btn-pay' type='button' value='去结算'></li>
</ul>
<hr>
</div>
</template>
<script>
import TodoList from './components/TodoList'
export default {
data(){
return {
productItems: ['商品', '数量', '单价(元)', '金额(元)', '操作'],
products: [
{
id: 0,
desc: {
name: '[1]香蕉',
factory: '[1]未知',
description: '[1]助消化',
origin: '[1]未知'
},
imgPath: require('../t2/file/test.jpg'),
monkeyIcon: '¥',
price: 10,
num: 0,
totalPrice: 0,
checked: false
},
{
id: 1,
desc: {
name: '[2]橘子',
factory: '[2]未知',
description: '[2]热属性水果',
origin: '[2]未知'
},
imgPath: require('../t2/file/test.jpg'),
monkeyIcon: '¥',
price: 20,
num: 0,
totalPrice: 0,
checked: false
},
{
id: 2,
desc: {
name: '[3]苹果',
factory: '[3]未知',
description: '[3]最最平常的水果电饭锅水电费感受到腹背受敌非布司他封闭式的分别是电饭煲',
origin: '[3]未知'
},
imgPath: require('../t2/file/test.jpg'),
monkeyIcon: '¥',
price: 30,
num: 0,
totalPrice: 0,
checked: false
},
{
id: 3,
desc: {
name: '[4]酸奶',
factory: '[4]未知',
description: '[4]补充营养',
origin: '[4]未知'
},
imgPath: require('../t2/file/test.jpg'),
monkeyIcon: '¥',
price: 40,
num: 0,
totalPrice: 0,
checked: false
}
],
content: '这里是测试',
checkedAll: false,
monkeyIcon: '¥',
rawData: []
}
},
computed: {
numAll(){
return this.products.reduce((total, product)=>{
total += product.checked?product.num:0;
return total}, 0);
},
allPrice(){
return this.products.reduce((total, product)=>{
total += product.checked?product.totalPrice:0;
return total}, 0);
}
},
methods: {
deleteProduct(id){
this.products.forEach((product, index)=>{
if(product.id === id){
this.products.splice(index, 1)
}
})
},
changeChecked(){
this.checkedAll = !this.checkedAll;
this.products.forEach((product)=>{
product.checked = this.checkedAll;
})
},
deleteCheckedProducts(){
this.products = this.products.filter((product)=>{
if(!product.checked){
return true;
}
})
},
continueBuy(){
this.products = [];
this.rawData.forEach((product)=>{
this.products.push(Object.assign({}, product))
})
this.checkedAll = false;
},
},
created() {
this.products.forEach((product)=>{
this.rawData.push(Object.assign({}, product))
})
},
components: { TodoList }
}
</script>
<style scoped>
ul{
list-style: none;
margin: 0;
padding: 0;
}
ul>li{
margin: 0;
padding: 0;
}
ul.item-desc, ul.operate-item{
min-width: 900px;
width: 100%;
border: 1px solid #e3e3e3;
font-size: 0.9rem;
font-weight: 400;
text-align: center;
display: -webkit-flex;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
ul.item-desc li{
max-height: 100%;
width: 15%;
margin: 0;
padding: 0;
line-height: 2;
text-align: center;
vertical-align: middle;
}
ul.item-desc li:nth-child(2){
width: 32%;
}
ul.item-desc li:nth-child(1){
width: 8%;
}
ul.operate-item li{
max-height: 100%;
width: 10%;
font-weight: 700;
}
ul.operate-item li input[type='button']{
border: 0;
background: transparent;
font-weight: 700;
outline: none;
}
.btn-pay{
border: 1px solid #FF8C00 !important;
background: #FF8C00 !important;
line-height: 2;
width: 100%;
}
ul.operate-item li:nth-child(3){
width: 70%;
line-height: 1;
text-align: right;
padding-right: 10px;
}
ul.operate-item li:nth-child(3) span{
color: red;
}
</style>
TodoList.vue
<template>
<ul class='list'>
<li><input type='checkbox' :checked='product.checked' @change='product.checked=!product.checked'></li>
<li>
<img :src='product.imgPath' alt='图片'>
<p>
<span>{{ product.desc.name }}</span><br>
<span>{{ product.desc.factory }}</span><br>
<span>{{ product.desc.description }}</span><br>
<span>{{ product.desc.origin }}</span>
</p>
</li>
<li>
<CountInput
:num='product.num'
@update:num = 'changeAllPrice($event)'
></CountInput>
</li>
<li class='red'>{{ product.monkeyIcon }}{{ product.price }}</li>
<li class='red'>{{ product.monkeyIcon }}{{ product.totalPrice }}</li>
<li><button @click='$emit("delete", product.id)'>删除</button></li>
</ul>
</template>
<script>
import CountInput from './CountInput.vue'
export default {
props: {
product: {
type: Object,
required: true
}
},
methods: {
changeAllPrice(num){
this.product.num = num;
this.product.totalPrice = this.product.price * this.product.num;
}
},
components: { CountInput }
}
</script>
<style scoped>
.list{
font-size: 16px;
border: 1px solid #e3e3e3;
height: 70px;
min-width: 900px;
width: 100%;
list-style: none;
padding: 0;
display: -webkit-flex;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.list li{
max-height: 100%;
width: 15%;
margin: 0;
padding: 0;
text-align: center;
vertical-align: middle;
}
.list li:nth-child(2){
width: 32%;
}
.list li:nth-child(1){
width: 8%;
}
.list li>img{
width: 30%;
height: 80%;
}
.list li>p{
font-size: 0.5rem;
width: 70%;
margin: 0;
padding: 0;
line-height: 100%;
display: inline-block;
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.list li>p>span:first-child{
line-height: 1.5;
font-weight: 800;
}
.red{
color: red;
}
</style>
CountInput.vue
<template>
<div class='input-count'>
<input type='button' value='-' @click='modifyNum("reduce")'>
<BaseInput class='input-text' :value='num' @input='$emit("update:num", $event)'></BaseInput>
<input type='button' value='+' @click='modifyNum("add")'>
</div>
</template>
<script>
import BaseInput from './BaseInput'
export default {
props: {
num: {
type: Number,
required: true,
default: 5
}
},
methods: {
modifyNum(state){
var d = state === 'reduce'?this.num-1: this.num+1;
d = d>0?d:0
this.$emit('update:num', d)
// if(typeof state === 'number'){
// this.$emit('update:num', state)
// }else{
// var d = state === 'reduce'?this.num-1: this.num+1;
// d = d>0?d:0
// this.$emit('update:num', d)
// }
}
},
components: {BaseInput}
}
</script>
<style scoped>
.input-count{
border: 1.5px solid #e3e3e3;
padding: 0;
text-align: center;
width: 80px;
height: 25px;
vertical-align: top;
margin: auto;
}
.input-count>input[type='button']{
height: 100%;
width: 20px;
text-align: center;
background: #FFF;
border: 0px;
}
.input-count>.input-text{
border: 0px;
border-left: 1.5px solid #e3e3e3;
border-right: 1.5px solid #e3e3e3;
height: 100%;
width: 40px;
margin: 0;
padding: 0;
text-align: center;
box-sizing: border-box;
background: #FFF;
}
</style>
BaseInput.vue
<template>
<input
type='text'
:value='value'
@input='modifyNum($event.target.value)'>
</template>
<script>
export default {
model: {
prop: 'value',
event: 'input'
},
props: {
value: {
type: Number,
required: true,
default: 0
}
},
methods: {
modifyNum(data){
var d = parseInt(data.replace(/[^\d]/, '')) || 0;
this.$forceUpdate()
this.$emit('input', d)
}
}
}
</script>
- 智障代码理解
BaseInput.vue
CountInput.vue
TodoList.vue
App.vue
- 结尾
主要是不熟悉怎么布局,这里待再练习段时间就去分析别人的代码。
知识获得: 数据的流向操作和事件的处理。
– 这里数据直接在App.vue里面定义,后面再修改就是使用store、vuex。
结构是乱七八糟的, 差不多就这样。
第一个稍微有点内容的东西,很多知识点细节看的时候懂了用起来似懂非懂,做完这个,虽简单,但巩固了最最基础的基础。
加油!