• 背景
    囫囵吞枣的看了一遍vue,做这个理解一下很浅显的知识(没有经验,有点乱七八糟),算是第一版,以后每进步一些能改的话就改一点。
  • 结果图(css还是不熟练)
    -vue做购物清单总结记录
  • 代码
    四个文件:

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>&nbsp;件商品总计(不含运费):<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
vue做购物清单总结记录
CountInput.vue
vue做购物清单总结记录
TodoList.vue
vue做购物清单总结记录
App.vue
vue做购物清单总结记录vue做购物清单总结记录

  • 结尾
    主要是不熟悉怎么布局,这里待再练习段时间就去分析别人的代码。
    知识获得: 数据的流向操作和事件的处理。
    – 这里数据直接在App.vue里面定义,后面再修改就是使用store、vuex。

结构是乱七八糟的, 差不多就这样。
第一个稍微有点内容的东西,很多知识点细节看的时候懂了用起来似懂非懂,做完这个,虽简单,但巩固了最最基础的基础。

加油!

相关文章:

  • 2021-09-11
  • 2022-12-23
  • 2021-12-04
  • 2022-12-23
  • 2021-12-04
  • 2022-12-23
  • 2022-01-18
  • 2022-01-17
猜你喜欢
  • 2022-01-18
  • 2021-08-28
  • 2021-07-14
  • 2022-12-23
  • 2021-11-10
  • 2021-04-05
  • 2021-11-30
相关资源
相似解决方案