2024字节青训营笔记(六) Vue核心(2)

54 阅读3分钟

class,style绑定

字符串写法,类名不确定

<div id="root">
        <div class="basic" :class="mood" @click="changeMood"></div>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                mood: 'sad'
            },
            methods: {
                changeMood() {
                    this.mood = 'happy'
                }
            }
        })
    </script>

实现点击随机切换颜色

<div id="root">
        <div class="basic" :class="mood" @click="changeMood"></div>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                mood: 'sad'
            },
            methods: {
                changeMood() {
                    const arr = ['sad', 'happy', 'normal']
                    const index = Math.floor(Math.random() * 3)
                    this.mood = arr[index]
                }
            }
        })
    </script>

数组写法:类名不确定,个数不确定

<div class="basic" :class="classArr">{{name}}</div>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                name: 'lyt',
                mood: 'sad',
                classArr: ['atlyt1', 'atlyt2', 'atlyt3']
            }
        })
    </script>

对象写法:个数确定,名字确定

<div class="basic" :class="classObj">{{name}}</div>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                name: 'lyt',
                mood: 'sad',
                classObj: {
                    atlyt1: false,
                    atlyt2: false
                }
            }
           
        })

style绑定

<div class="basic" :style="{fontSize: fsize+'px'}">{{name}}</div>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                name: 'lyt',
                mood: 'sad',
                // classArr: ['atlyt1', 'atlyt2', 'atlyt3'],
                // classObj: {
                //     atlyt1: false,
                //     atlyt2: false

                // },
                fsize: 40
            }
        })

对象写法

<div class="basic" :style="styleObj">{{name}}</div>
    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                name: 'lyt',
                mood: 'sad',
                // classArr: ['atlyt1', 'atlyt2', 'atlyt3'],
                // classObj: {
                //     atlyt1: false,
                //     atlyt2: false

                // },
                styleObj: {
                    fontSize: '40px'
                }
            }
        })

条件渲染

v-show

结构还在

v-if

结构直接没了

所以v-if用于变化没那么频繁的

多个判断:else-if, else

<div v-if="n===1">第一个</div>
<div v-else-if="n===2">第二个</div>
<div v-else-if="n===3">第三个</div>

template和v-if配合使用

<template v-if="n===1">
            <h2>你好</h2>
            <h2>lyt</h2>
            <h2>hhhh</h2>
        </template>

列表渲染

遍历数组:(用得多)

v-for

:key 作为标识

<div id="root">
        <ul>
            <li v-for="p in persons" :key="p.id">
                {{p.name}}-{{p.age}}</li>
        </ul>
    </div>
    <script>
        new Vue({
            el: '#root',
            data: {
                persons: [
                    { id: '001', name: '张三', age: '18' },
                    { id: '002', name: '李四', age: '19' },
                    { id: '003', name: '王五', age: '20' }
                ]
            }
        })
    </script>

也可这样写

<ul>
            <li v-for="(p,index) in persons" :key="index">
                {{p.name}}-{{p.age}}</li>
        </ul>

遍历对象:

<ul>
            <li v-for="(value,k) of car" :key="k">
                {{k}}-{{value}}
            </li>
</ul>

        car: {
                    name: '奥迪A8',
                    price: '70万',
                    color: '黑色'
                }

遍历字符串:

<ul>
            <li v-for="(char,index) of str" :key="index">
                {{index}}-{{char}}
            </li>
        </ul>

        str: 'hello'

遍历指定次数(用得少)

<ul>
            <li v-for="(number,index) of 5" :key="index">
                {{index}}-{{number}}
            </li>
        </ul>

key的原理

用index作为key

用p.id (数据的唯一标识)

对比规则:内容不一样就用新的,一样就用旧的

对数据破坏顺序,用index就可能出问题

如果不写key,自动用遍历时的index作为key,所以不写key也会错

列表的过滤

1.另找一个数组来存数据,不要把原数组删掉

2.indexOf(' ')==0 ,所有数据都可以有

所以要用immadiate:true来先执行一次,才会有数据显示

watch实现:

<body>
    <div id="root">
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <ul>
            <li v-for="(p,index) in filPersons" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>

    </div>
    <script>
        new Vue({
            el: '#root',
            data: {
                keyWord: '',
                persons: [
                    { id: '001', name: '马冬梅', age: '18', sex: '女' },
                    { id: '002', name: '周冬雨', age: '19', sex: '女' },
                    { id: '003', name: '周杰伦', age: '20', sex: '男' },
                    { id: '004', name: '温兆伦', age: '21', sex: '男' }
                ],
                filPersons: []
            },

            watch: {
                keyWord: {
                    immediate: true,
                    handler(val) {
                        this.filPersons = this.persons.filter((p) => {
                            return p.name.indexOf(val) !== -1
                        })
                    }
                }
            }
        })
    </script>

用computed:

<script>

        new Vue({
            el: '#root',
            data: {
                keyWord: '',
                persons: [
                    { id: '001', name: '马冬梅', age: '18', sex: '女' },
                    { id: '002', name: '周冬雨', age: '19', sex: '女' },
                    { id: '003', name: '周杰伦', age: '20', sex: '男' },
                    { id: '004', name: '温兆伦', age: '21', sex: '男' }
                ]

            },
            computed: {
                filPersons() {
                    return this.persons.filter((p) => {
                        return p.name.indexOf(this.keyWord) !== -1
                    })
                }
            }
        })
    </script>

列表排序

sortType在计算属性里面

计算属性改变,filPersons就会重新赋值

太妙了!!!!!!多看几遍!

<div id="root">
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <button @click="sortType=2">年龄升序</button>
        <button @click="sortType=1">年龄降序</button>
        <button @click="sortType=0">年龄原序</button>
        <ul>
            <li v-for="(p,index) in filPersons" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>

    </div>
    <script>

        new Vue({
            el: '#root',
            data: {
                sortType: 0,
                keyWord: '',
                persons: [
                    { id: '001', name: '马冬梅', age: '30', sex: '女' },
                    { id: '002', name: '周冬雨', age: '31', sex: '女' },
                    { id: '003', name: '周杰伦', age: '18', sex: '男' },
                    { id: '004', name: '温兆伦', age: '19', sex: '男' }
                ]

            },
            computed: {
                filPersons() {
                    const arr = this.persons.filter((p) => {
                        return p.name.indexOf(this.keyWord) !== -1
                    })

                    if (this.sortType) {
                        arr.sort((p1, p2) => {
                            return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
                        })
                    }
                    return arr
                }
            }
        })
    </script>

vue本身就有默认的监视

配置watch就会用到

检测数据的原理:

this.persons[0] = { id: '001', name: '张老师', age: '50' }

先点了更新,但是没更新

自己模拟一个监视,死循环:

模拟数据代理:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
</head>

<body>

    <script>
        let data = {
            name: '中南民族大学',
            address: '北京',
            a: {
                b: 1
            }
        }

        const obs = new Observer(data)
        console.log(obs)
        //创建一个监视实例对象用于监视data中属性变化

        //准备一个vm实例对象
        let vm = {}
        vm._data = data = obs


        //底层构造函数,收到一个对象作为参数
        function Observer(obj) {
            const keys = Object.keys(obj)
            //keys是一个数组,有obj的属性

            keys.forEach((k) => {
                //this是实例对象,k是其中遍历到的一个属性
                Object.defineProperty(this, k, {
                    get() {
                        return obj[k]
                    },
                    set(val) {
                        console.log(`${k}更改了,我要去解析模板生成虚拟DOM`)

                        obj[k] = val
                    }
                })
            })

        }

    </script>

</body>

</html>

把obs给vm实例对象,同时也给data,这样这三个都相等

修改值:data和vm._data都绑定在obs上了,只要它们有变化obs调用set,三个都会同时改变

Vue更完善的地方:

可以直接vm.name(做了数据代理)

对象中还有对象,a里面的b没有set

递归,想有多少个对象,就有多少个set

数组的数据监测

但是这样写,在页面中不会有显示,也就是在这个时候添加属性是没有用的

用Vue.set(): 有响应了

vm.$set()

回忆数据代理

所以可以简写