【vue3】04-vue基础语法补充及阶段案例

vue基础语法补充

vue的computed

computed:用于声明要在组件实例上暴露的计算属性。(官方文档描述)

我们已经知道,在模板中可以直接通过插值语法显示一些data中的数据

但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示

  • 比如我们需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示;
  • 在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算;
  • 在模板中放入太多的逻辑会模板过重难以维护;

而且因为多个地方都使用到,所以会有大量重复的代码,那么我们可以将逻辑抽离出去:

  • 比如直接逻辑抽取到一个method中,放到methods的options中;
  • 但是,这种做法有一个直观的弊端,就是所有的data使用过程都会变成了一个方法的调用,所以正确的做法应该是抽离出来后放入计算属性computed中

用法示例:

    <div id="app">
        <h2>{{fullName}}</h2>

        <!-- 2.显示分数等级 -->
        <h2>{{getScorelevel}}</h2>

        <!-- 3.反转单词显示文本 -->
        <h2>{{reverseMessage}}</h2>
    </div>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    // 1.姓名
                    firstName: "kobe",
                    lastName: "byrant",
                    // 2.分数及不及格
                    score: 65,
                    // 3.一串文本:对文本中的单词进行反转显示
                    message: "my name is sevgilid"

                }
            },
            methods: {

            },

            computed: {
                // 计算属性对应的是一个函数(经过响应式复杂逻辑转化的都应写在computed里)
                // 计算属性是有缓存的
                fullName() {
                    return this.firstName + "" + this.lastName
                },

                getScorelevel() {
                    return this.score > 60 ? '及格' : '不及格'
                },

                reverseMessage() {
                    return this.message.split("").reverse().join("")
                }

            }
        })
        app.mount('#app')
    </script>

vue的watch侦听

watch:用于声明在数据更改时调用的侦听回调。(官方文档描述

什么是侦听器呢?

  • 开发中我们在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中;
  • 当数据变化时,template会自动进行更新来显示最新的数据;
  • 但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要用侦听器watch来完成了;

用法:{ [key: string]: string | Function [ Object | Array}

如下示例:

点击按钮后message就会修改,且控制台打印’‘message发生了改变’’

    <div id="app">
        <h2>{{message}}</h2>
        <button @click="changeMessage">修改message</button>
    </div>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    message: 'hello vue'
                }
            },
            methods: {
                changeMessage() {
                    this.message = "你好啊,李二狗"
                }
            },
            watch: {
                message() {
                    console.log("message发生了改变");
                }
            }
        })
        app.mount('#app')
    </script>

通过以上例子发现其实就是想监听谁在里面写谁,但这样使用的话只知道数据发生了改变,并不知道改变是什么。

  1. 其实回调函数里默认是有传过来两个参数的:分别是newvalue,oldvalue,像下面这样修改代码后就可以看到前后数据发生的改变:
    watch: {
        message(newValue,oldValue) {
        console.log("message已发生改变", newValue, oldValue);
      }

打印结果:

在这里插入图片描述

  1. 如果是监听的是一个对象类型,那么拿到的是代理对象,可以通过newValue.name这样去拿值
 <div id="app">
        <h2>{{info}}</h2>
        <button @click="changeInfo">改变info</button>
    </div>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    info:{name:"daa",age:15}
                }
            },
            methods: {
                changeInfo(){
                    this.info={name:"kkk",age:25}
                }
            },
            watch: {
                info(newValue,oldValue){
                    console.log("info数据发生了变化", newValue,oldValue);
                    console.log(newValue.name,oldValue.name);![在这里插入图片描述](https://img-blog.csdnimg.cn/9a9764dc762549caa4d9e4905b6336ea.png)

                }
            }
        })
        app.mount('#app')
    </script>

控制台打印结果:

在这里插入图片描述

  • 如果想拿到原生对象:Vue.toRaw(newValue)在这里插入图片描述
  1. watch的侦听选项配置:
  • deep:true:为true时进行深度监听
  • immediate:true:为true时第一次渲染直接执行一次监听器

其实默认是不进行深度监听的,像下面的例子:

  • 如果修改的是整个info是可以监听到的
  • 但是只修改info对象中的一个属性是监听不到
 <script>

        const app = Vue.createApp({
            data() {
                return {
                    info: {name:"kkk", age:25}
                }
            },

            methods:{
                changeInfo(){
                    // 1.修改原对象,可以监听
                    // this.info = {name:"wxx", age:52}

                    // 2.直接修改原对象的一个属性
                    this.info.name = "sevgilid"
                }
            },

            watch:{
                // 默认watch监听不会进行深度监听(所以只改变属性时未监听到)
                // info(newValue,oldValue){
                //     console.log("info数据发生了改变", newValue,oldValue);
                // }

                // 进行深度监听
                info:{
                    handler(newValue,oldValue){
                        console.log("info一发生改变",newValue, oldValue);
                    },
                    // 监听器选项:
                    //info进行深度监听:加上以下配置后即可监听到属性改变
                    deep:true,
                    // 第一次渲染直接执行一次监听器
                    immediate:true
                }

            
            }
        })
        app.mount('#app')
    </script>

书籍购物车案例

一个相对综合的案例,可以对前面几篇博客知识进行练习(完整代码在文末

在这里插入图片描述

案例说明:
1.在界面上以表格的形式,显示一些书籍的数据;
2.在底部显示书籍的总价格;
3.点击+或者-可以增加或减少书籍数量(如果为1,那么不能继续-);
4.点击移除按钮,可以将书籍移除(当所有的书籍移除完毕时,显示:购物车为空);
5.点击行变色

案例步骤:
1.搭建界面内容:做出表格,调整基本样式
2.获取数据:可以从后台拿数据,这里选择自己在data中模拟数据
3.分析实现逻辑:

  • 使用v-for遍历数据配合插值语法实现界面的动态填充
  • 为按钮绑定methods中的方法,使用v-if判断为1时不能继续
  • 在computed计算属性中实现对价格及数量的逻辑抽取
  • 使用split方法移出
  • 为点击行动态绑定active样式

步骤代码详解:

遍历数据及加减:

在这里插入图片描述
在这里插入图片描述

注意事项:

  1. 遍历时外层使用template包裹
  2. v-for就要写key(自己写的时候忘记了)
  3. 因为绑定按钮的时候是动态绑定:所以点击事件的时候要传入参数,即拿到索引才能知道你点击的是哪一个按钮)
  4. 小于1不可再点击-1按钮时应:disabled={item<=1}

总价响应式:

在这里插入图片描述

注意事项:

  1. 抽取后写入computed计算属性,而非放入methods中进行方法的调用
  2. 遍历时内部不要忘记加上const

移出操作:

在这里插入图片描述
注意事项:

  1. 绑定事件时传递index参数来判断移出的是第几行
  2. slice()的使用

行变色:

  1. 通过点击获取索引index来判断点击的第几行
  2. 在data中定义currentIndex
  3. 点击事件中将获取到的index赋值给currentIndex
  4. tr动态绑定active时使用对象语法,通过判断index === currentIndex的布尔值来动态绑定

案例完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../Vue3.js"></script>
    <style>
        table {
            border-collapse: collapse;
            color: brown;
            text-align: center;
        }

        table,
        th,
        td {
            border: 1px solid black;
        }

        .active {
            background-color: aqua;
        }
    </style>

</head>

<body>
    <div id="app">
        <div class="shopCurt">
            <table>
                <thead>
                    <tr>
                        <th>序号</th>
                        <th>商品名字</th>
                        <th>价格</th>
                        <th>数量</th>
                        <th>商品描述</th>
                        <th>操作</th>
                    </tr>
                </thead>

                <tbody>
                    <template v-for="( item,index ) in infos">
                        <tr :class="{active:index === currentIndex}" @click="rowClick(index)">
                            <td>{{ index+1 }}</td>
                            <td>{{ item.name }}</td>
                            <td>{{ item.price }}</td>
                            <td><button @click="decrement(index)" :disabled="item.count<=1">-1</button>{{ item.count }}
                                <button @click="increment(index)">+1</button>
                            </td>
                            <td>{{ item.dec }}</td>
                            <td><button @click="removeBook(index)">{{ item.caozuo }}</button></td>
                        </tr>
                    </template>


                </tbody>
            </table>
        </div>
        <h2>AllPrice:{{ allPrice }}</h2>
    </div>
</body>


<script src="./Vue3.js"></script>
<script>
    const app = Vue.createApp({

        data() {
            return {
                currentIndex: -1,

                infos: [
                    { sort: 0, name: "华为电脑", price: 9.9, count: 1, dec: "9.9秒杀快来抢购", caozuo: "移除" },
                    { sort: 0, name: "iphoneX", price: 12.8, count: 1, dec: "苹果X最新出炉", caozuo: "移除" },
                    { sort: 0, name: "小米11Plus", price: 13.1, count: 1, dec: "速度来抢", caozuo: "移除" },
                    { sort: 0, name: "外星人电脑", price: 56, count: 1, dec: "真的便宜", caozuo: "移除" },
                    { sort: 0, name: "OPPOR11", price: 100, count: 1, dec: "好用不贵", caozuo: "移除" }
                ]
            }
        },
        computed: {
            allPrice() {
                let price = 0;
                for (const item of this.infos) {
                    price += item.price * item.count
                }
                return price
            }

        },
        methods: {
            // 监听加减按钮
            increment(index) {
                this.infos[index].count++
            },
            decrement(index) {
                this.infos[index].count--
            },
            // 监听行点击变色
            rowClick(index) {
                this.currentIndex = index;
            },
            // 移出操作
            removeBook(index) {
                this.infos.splice(index, 1)
            }
        }
    })
    app.mount('#app')
</script>

</html>

实现效果:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值