Vue学习二:指令补充、computed计算属性、watch侦听器、案例:水果购物车

发布时间 2023-09-11 21:24:53作者: 数星观月

一、指令修饰符

通过"."指明一些指令后缀,不同后缀封装了不同的处理操作 → 简化代码
①按键修饰符
@keyup.enter → 键盘回车监听
②v-model修饰符
v-model.trim →去除首尾空格
v-model.number →转数字
③事件修饰符
@事件名.stop →阻止冒泡
@事件名.prevent →阻止默认行为

二、V-bind对样式控制的增强

操作class

语法 :class= "对象/数组"
①对象→键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类

使用场景:固定类名,来回切换是否使用

<div :class="{类名1:布尔值,类名2:布尔值}"></div>

②数组→数组中所有的类,都会添加到盒子上,本质就是一个class列表

使用场景:批量添加或删除类

<div :class="[类名1,类名2,类名3]"></div>

操作style

语法 :style= "样式属性"

使用场景:具体某个属性的动态设置

<div :style="{CSS属性名1:CSS属性值,CSS属性名2:CSS属性值}"></div>

案例进度条如下,使用layui的进度条

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./vue.js"></script>
        <link rel="stylesheet" href="./layui/css/layui.css"  media="all">
    </head>
    <body>
        <div id="box01">
            <div class="layui-progress" :style="{width:'300px',height:'50px'}">
              <div class="layui-progress-bar" :style="{width:percent+'%',height:'50px'}"></div>
            </div>
            <button @click="percent = 25">进度25%</button>
            <button @click="percent = 50">进度50%</button>
            <button @click="percent = 75">进度75%</button>
            <button @click="percent = 100">进度100%</button>
        </div>
        <script>
            const app = new Vue({
                el:'#box01',
                data:{
                    percent:0,
                }
            })
        </script>
        <script src="./layui/layui.js" charset="utf-8"></script>
        <script>
        layui.use('element', function(){
          var element = layui.element;
        });
        </script>
    </body>
</html>
View Code

三、v-model应用于其他表单元素

常见的表单元素都可以用v-model绑定关联→快速获取或设置表单元素的值,它会根据控件类型自动选取正确的方法来更新元素
四、计算属性

概念:基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算。
语法:
①声明在computed配置项中,一个计算属性对应一个函数
②使用起来和普通属性一样使用{{计算属性名}}

案例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./vue.js"></script>
        <link rel="stylesheet" href="./layui/css/layui.css"  media="all">
    </head>
    <body>
        <div id="box01">
            <table>
                <tr>
                    <th>名字</th>
                    <th>数量</th>
                </tr>
                <tr v-for="item in msg" :key="item.id">
                    <td>{{item.name}}</td>
                    <td>{{item.num}}个</td>
                </tr>
            </table>
            <p>数量总计:{{totalNum}}个</p>
        </div>
        <script>
            const app = new Vue({
                el:'#box01',
                data:{
                    msg:[
                        {id:1,name:'篮球',num:4},
                        {id:2,name:'足球',num:6},
                        {id:3,name:'排球',num:9}
                    ]
                },
                computed:{
                    totalNum(){
                        let totalnum = this.msg.reduce((sum,item)=>sum+item.num,0)
                        return totalnum
                    }
                }
            })
        </script>
        <script src="./layui/layui.js" charset="utf-8"></script>
    </body>
</html>
View Code

计算属性完整写法
计算属性默认的简写,只能读取访问,不能"修改"。
如果要"修改"→需要写计算属性的完整写法。

computed:{
    计算属性名(){
        一段代码逻辑(计算逻辑)
        return 结果
    }
}
<!--完整计算属性写法-->
computed:{
    计算属性名:{
        get(){
            一段代码逻辑(计算逻辑)
            return 结果
        }
        set(修改的值){
            一段代码逻辑(修改逻辑)
        }
    }
}

成绩案例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./vue.js"></script>
        <link rel="stylesheet" href="./layui/css/layui.css"  media="all">
        <style>
            .tableStyle{
                border:1px solid silver;
                width:400px;
                height: 200px;
                margin-left: 50px;
                text-align: center;
            }
            tr,td,th {
                border: 1px solid silver;
                align: center;
            }
            .red{
                color: red;
            }
        </style>
    </head>
    <body>
        <div id="box01">
            <table class="tableStyle">
                <thead>
                    <tr>
                        <th>编号</th>
                        <th>科目</th>
                        <th>成绩</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody v-if="list.length > 0">
                    <tr v-for="(item,index) in list" :key="item.id">
                        <td>{{index+1}}</td>
                        <td>{{item.subject}}</td>
                        <td :class="{red:item.score < 60}">{{item.score}}</td>
                        <td><a @click="del(item.id)" href="#">删除</a></td>
                    </tr>
                </tbody>
                <tbody v-else>
                    <tr>
                        <td colspan="4">暂时无数据</td>
                    </tr>
                </tbody>
                <tfoot>
                    <tr>
                        <td colspan="2">总分:{{totalScore}}</td>
                        <td colspan="2">平均分:{{averageScore}}</td>
                    </tr>
                </tfoot>
            </table>
            <form class="layui-form" action="">
              <div class="layui-form-item">
                <label class="layui-form-label">科目</label>
                <div class="layui-input-block">
                  <input v-model="subject" type="text" >
                </div>
              </div>
              <div class="layui-form-item">
                <label class="layui-form-label">分数</label>
                <div class="layui-input-block">
                  <input v-model="score" type="number">
                </div>
              </div>
              <div class="layui-form-item">
                <div class="layui-input-block">
                  <button @click="add" class="layui-btn" lay-submit lay-filter="formDemo">添加</button>
                </div>
              </div>
            </form>
        </div>
        <script>
            const app = new Vue({
                el:'#box01',
                data:{
                    subject:'',
                    score:'',
                    list:[
                        {id:1,subject:'语文',score:45},
                        {id:2,subject:'数学',score:65},
                        {id:3,subject:'英语',score:85},
                        {id:4,subject:'科学',score:90},
                    ]
                },
                methods:{
                    del(id){
                        this.list = this.list.filter(item=>item.id != id)
                    },
                    add(){
                        if(!this.subject){
                            alert("请输入科目")
                            return
                        }
                        let score = parseFloat(this.score)
                        if(score < 0 || score > 100){
                            alert("请输入正确的成绩")
                            return
                        }
                        this.list.unshift({
                            id:+new Date(),
                            subject:this.subject,
                            score:score
                        })
                        this.subject = ''
                        this.score = ''
                    }
                },
                computed:{
                    totalScore(){
                        return this.list.reduce((sum,item)=>sum+item.score,0)
                    },
                    averageScore(){
                        return this.list.reduce((sum,item)=>sum+item.score,0)/this.list.length
                    }
                }
            })
        </script>
        <script src="./layui/layui.js" charset="utf-8"></script>
        <script>
        //Demo
        layui.use('form', function(){
          var form = layui.form;
          
          //监听提交
          form.on('submit(formDemo)', function(data){
            layer.msg(JSON.stringify(data.field));
            return false;
          });
        });
        </script>
    </body>
</html>
View Code

五、watch侦听器

作用:监视数据变化,执行一些业务逻辑或异步操作。
语法:
①简单写法→简单类型数据,直接监视
②完整写法→添加额外配置项

(1) deep: true对复杂类型深度监视
(2) immediate: true初始化立刻执行一次handler方法

watch:{
    数据属性名(newValue,oldValue){
        一些业务逻辑 或 异步操作
    },
    '对象.属性名'(newValue,oldValue){
        一些业务逻辑 或 异步操作
    }
}

案例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./vue.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <link rel="stylesheet" href="./layui/css/layui.css"  media="all">
        <style>
            #box01{
                margin: 50px 50px;
            }
            .translateBox01{
                width:200px;
                height: 200px;
                background-color: antiquewhite;
                float: left;
            }
            .translateBox02{
                width:200px;
                height: 200px;
                background-color:beige;
                float: left;
            }
        </style>
    </head>
    <body>
        <div id="box01">
            <h3>中文翻译成意大利语</h3>
            <div>
                <textarea v-model="obj.words" placeholder="请输入你要翻译的内容" class="translateBox01"></textarea>
            </div>
            <div class="translateBox02">
                {{result}}
            </div>
        </div>
        <script>
            const app = new Vue({
                el:'#box01',
                data:{
                    obj:{
                        words:''
                    },
                    result:''
                },
                watch:{
                    数据属性名(newValue,oldValue){
                        一些业务逻辑 或 异步操作
                    },
                    '对象.属性名'(newValue,oldValue){
                        一些业务逻辑 或 异步操作
                    }
                    'obj.words'(newValue){
                        clearTimeout(this.timer)
                        this.timer = setTimeout(async ()=>{
                            const res = await axios({
                                url:'https://applet-base-api-t.itheima.net/api/translate',
                                params:{
                                    words:newValue
                                }
                            })
                            this.result = res.data.data
                            console.log(res)
                        },300)
                    }
                }
            })
        </script>
        <script src="./layui/layui.js" charset="utf-8"></script>
    </body>
</html>
View Code

六、水果购物车

html代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./vue.js"></script>
        <link rel="stylesheet" href="./layui/css/layui.css"  media="all">
        <link rel="stylesheet" href="css/shopCart.css" />
    </head>
    <body>
        <div id="box01">
            <table id="cartTable">
                    <thead>
                        <tr>
                            <th><label><input class="check-all check" type="checkbox"/>&nbsp;全选</label></th>
                            <th>商品</th>
                            <th>单价</th>
                            <th>数量</th>
                            <th>小计</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="(item,index) in list" :key="item.id">
                            <td class="checkbox">
                                <input v-model="item.isChecked" class="check-one check" type="checkbox" />
                            </td>
                            <td class="goods"><img :src="item.icon" alt="" /><span></span></td>
                            <td class="price">{{item.price}}</td>
                            <td class="count">
                                <button class="reduce" @click="item.num--" :disabled="item.num <= 1">-</button>
                                <input v-model="item.num" class="count-input" type="text" />
                                <button class="add" @click="item.num++">+</button></td>
                            <td class="subtotal">{{item.num * item.price}}</td>
                            <td @click="del(item.id)" class="operation"><span class="delete">删除</span></td>
                        </tr>
                    </tbody>
                </table>
            
                <div class="foot" id="foot">
                    <label class="fl select-all"><input v-model="isAll" type="checkbox" class="check-all check"/>&nbsp;全选</label>
                    <div class="fr closing">结 算</div>
                    <div class="fr total">合计:¥<span id="priceTotal">{{totalPrice}}</span></div>
                    <div class="fr selected" id="selected">已选商品
                        <span id="selectedTotal">{{totalCount}}</span><span class="arrow up"></span>
                        <span class="arrow down"></span>
                    </div>
                    <div class="selected-view">
                        <div id="selectedViewList" class="clearfix">
                        </div>
                        <span class="arrow"><span></span></span>
                    </div>
                </div>
        </div>
        <script>
            const app = new Vue({
                el:'#box01',
                data:{
                    list:[
                        {
                            id:1,
                            icon:'./img/beautifulGirl01.PNG',
                            isChecked:false,
                            num:2,
                            price:5999
                        },
                        {
                            id:2,
                            icon:'./img/beautifulGirl02.PNG',
                            isChecked:true,
                            num:6,
                            price:3988
                        },
                        {
                            id:3,
                            icon:'./img/beautifulGirl03.PNG',
                            isChecked:false,
                            num:9,
                            price:9999
                        },
                        {
                            id:4,
                            icon:'./img/beautifulGirl04.PNG',
                            isChecked:false,
                            num:2,
                            price:2689
                        },
                        {
                            id:5,
                            icon:'./img/beautifulGirl05.PNG',
                            isChecked:false,
                            num:12,
                            price:4599
                        },
                    ]
                },
                methods:{
                    del(id){
                        this.list = this.list.filter(item => item.id != id)
                    }
                },
                computed:{
                    isAll:{
                        get(){
                            return this.list.every(item => item.isChecked)
                        },
                        set(value){
                            this.list.forEach(item => item.isChecked = value)
                        }
                    },
                    totalCount(){
                        return this.list.reduce((sum,item)=> item.isChecked == true ? sum +=item.num:sum,0)
                    },
                    totalPrice(){
                        return this.list.reduce((sum,item)=> item.isChecked == true ? sum +=item.num*item.price:sum,0)
                    }
                }
            })
        </script>
        <script src="./layui/layui.js" charset="utf-8"></script>
    </body>
</html>
View Code

css样式

* {
    margin: 0;
    padding: 0;
}

a {
    color: #666;
    text-decoration: none;
}

body {
    padding: 20px;
    color: #666;
}

.fl {
    float: left;
}

.fr {
    float: right;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
    border: 0;
    text-align: center;
    width: 937px;
}

th,
td {
    border: 1px solid #CADEFF;
}

th {
    background: #e2f2ff;
    border-top: 3px solid #a7cbff;
    height: 30px;
}

td {
    padding: 10px;
    color: #444;
}

tbody tr:hover {
    background: RGB(238, 246, 255);
}

.checkbox {
    width: 60px;
}

.goods {
    width: 300px;
}

.goods span {
    width: 180px;
    margin-top: 20px;
    text-align: left;
    float: left;
}

.price {
    width: 130px;
}

.count {
    width: 90px;
}

.count .add,
.count input,
.count .reduce {
    float: left;
    margin-right: -1px;
    position: relative;
    z-index: 0;
}

.count .add,
.count .reduce {
    height: 23px;
    width: 17px;
    border: 1px solid #e5e5e5;
    background: #f0f0f0;
    text-align: center;
    line-height: 23px;
    color: #444;
}

.count .add:hover,
.count .reduce:hover {
    color: #f50;
    z-index: 3;
    border-color: #f60;
    cursor: pointer;
}

.count input {
    width: 50px;
    height: 15px;
    line-height: 15px;
    border: 1px solid #aaa;
    color: #343434;
    text-align: center;
    padding: 4px 0;
    background-color: #fff;
    z-index: 2;
}

.subtotal {
    width: 150px;
    color: red;
    font-weight: bold;
}

.operation {
    width: 80px;
}

.operation span:hover,
a:hover {
    cursor: pointer;
    color: red;
    text-decoration: underline;
}

img {
    width: 100px;
    height: 80px;
    /*border: 1px solid #ccc;*/
    margin-right: 10px;
    float: left;
}

.foot {
    width: 935px;
    margin-top: 10px;
    color: #666;
    height: 48px;
    border: 1px solid #c8c8c8;
    background-color: #eaeaea;
    background-image: linear-gradient(RGB(241, 241, 241), RGB(226, 226, 226));
    position: relative;
    z-index: 8;
}

.foot div,
.foot a {
    line-height: 48px;
    height: 48px;
}

.foot .select-all {
    width: 100px;
    height: 48px;
    line-height: 48px;
    padding-left: 5px;
    color: #666;
}

.foot .closing {
    border-left: 1px solid #c8c8c8;
    width: 100px;
    text-align: center;
    color: #000;
    font-weight: bold;
    background: RGB(238, 238, 238);
    cursor: pointer;
}

.foot .total {
    margin: 0 20px;
    cursor: pointer;
}

.foot #priceTotal,
.foot #selectedTotal {
    color: red;
    font-family: "Microsoft Yahei";
    font-weight: bold;
}

.foot .selected {
    cursor: pointer;
}

.foot .selected .arrow {
    position: relative;
    top: -3px;
    margin-left: 3px;
}

.foot .selected .down {
    position: relative;
    top: 3px;
    display: none;
}

.show .selected .down {
    display: inline;
}

.show .selected .up {
    display: none;
}

.foot .selected:hover .arrow {
    color: red;
}

.foot .selected-view {
    width: 935px;
    border: 1px solid #c8c8c8;
    position: absolute;
    height: auto;
    background: #ffffff;
    z-index: 9;
    bottom: 48px;
    left: -1px;
    display: none;
}

.show .selected-view {
    display: block;
}

.foot .selected-view div {
    height: auto;
}

.foot .selected-view .arrow {
    font-size: 16px;
    line-height: 100%;
    color: #c8c8c8;
    position: absolute;
    right: 330px;
    bottom: -9px;
}

.foot .selected-view .arrow span {
    color: #ffffff;
    position: absolute;
    left: 0px;
    bottom: 1px;
}

#selectedViewList {
    padding: 20px;
    margin-bottom: -20px;
}

#selectedViewList div {
    display: inline-block;
    position: relative;
    width: 100px;
    height: 80px;
    border: 1px solid #ccc;
    margin: 10px;
}

#selectedViewList div span {
    display: none;
    color: #ffffff;
    font-size: 12px;
    position: absolute;
    top: 0px;
    right: 0px;
    width: 60px;
    height: 18px;
    line-height: 18px;
    text-align: center;
    background: RGBA(0, 0, 0, .5);
    cursor: pointer;
}

#selectedViewList div:hover span {
    display: block;
}
View Code