# 1. 天气案例-计算属性实现/computed/methods

<div class="box">
    <h1>今天天气很 '{{get}}'</h1>
    <button @click="show">切换天气</button>
    <!-- @click="xxx" 绑定事件时xxx里可以写一些简单语句-->
    <!-- <button @click="name = !name">切换天气</button> -->
</div>
new Vue({
    el: '.box',
    data: {
        name: true
    },
    computed: {
        get() {
            return this.name ? '炎热' : '凉爽'
        }
    },
    methods: {
        show() {
            this.name = !this.name
        }   
    }
})

# 2. 天气案例-监听属性watch实现//immediate

  1. 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
  2. 监视的属性必须存在, 才能进行监视
  3. 监视属性的两种写法:
<div class="box">
    <h1>今天天气很 '{{get}}'</h1>
    <button @click="show">切换天气</button>
</div>
new Vue({
    el: '.box',
    data: {
        name: true
    },
    computed: {
        get() {
            return this.name ? '炎热' : '凉爽'
        }
    },
    methods: {
        show() {
            this.name = !this.name
        }   
    },
    watch: {
        name: {
            immediate: true, // 初始化时让name调用一下
        // 当nams发生改变时 handler会被调用
            handler(newvalue, oldvalue) {
                console.log('name被修改了', newvalue, oldvalue)
            }
        }   
    }
})
// vm.$watch('name', {
//     immediate: true,
//     handler(newvalue, oldvalue) {
//         console.log('name被修改了', newvalue, oldvalue)
//     } 
// })

# 3. 天气案例-深度监视实现/watch/deep

  1. Vue中的watch默认不监视对象内部值的改变(一层)
  2. 配置deep:true 可以监视对象内部值改变(多层)
  3. Vue自身可以监视对象内部值的改变, 但Vue提供的watch对象默认不可以
  4. 使用watch时根据数据的具体结构, 决定是否采用深度监视
<div class="box">
    <h1>今天天气很 '{{get}}'</h1>
    <button @click="show">切换天气</button>
    <hr>
    <h1>a的值是{{num.a}}</h1>
    <button @click="num.a++">点我让a+1</button>
    <h1>b的值是{{num.b}}</h1>
    <button @click="num.b++">点我让b+1</button>
    <button @click="num= {a: 666, b: 888}">点我彻底替换num</button>
</div>
new Vue({
    el: '.box',
    data: {
        name: true,
        num: {
            a: 1,
            b: 1
        }
    },
    computed: {
        get() {
            return this.name ? '炎热' : '凉爽'
        }
    },
    methods: {
        show() {
            this.name = !this.name
        }   
    },
    watch: {
        name: {
            handler(newvalue, oldvalue) {
                console.log('name被修改了', newvalue, oldvalue)
            }
        },
        // 监视多级结构中所有属性的变化
        'num': {
            deep: true,
            handler() {
                console.log('num被改变了')
            }
        }  
    }
})

# 4. 天气案例-深度监听简写

  • 不用deep和immediate属性时, 监听属性$watch才能简写
<div class="box">
    <h1>今天天气很 '{{get}}'</h1>
    <button @click="show">切换天气</button>
</div>
new Vue({
    el: '.box',
    data: {
        name: true
    },
    computed: {
        get() {
            return this.name ? '炎热' : '凉爽'
        }
    },
    methods: {
        show() {
            this.name = !this.name
        }   
    },
    watch: {
    // 1. 完整写法
        // name: {
        //     handler(newvalue, oldvalue) {
        //         console.log('name被修改了', newvalue, oldvalue)
        //     }
        // }
    // 2. 简写
        name(newvalue, oldvalue) {
            console.log('name被修改了', newvalue, oldvalue)
        }
    }
})
// 3. vm.$watch 的完整写法
// vm.$watch('name', {
//     handler(newvalue, oldvalue) {
//         console.log('name被修改了', newvalue, oldvalue)
//     }
// })

// 4. vm.$watch 的简写
// vm.$watch('name', function (newvalue, oldvalue) {
//     console.log('name被修改了', newvalue, oldvalue)
// })

# 5. computed和watch之间的区别

  1. computed能完成的功能, watch都可以完成

  2. watch能完成的功能, computed不一定能完成, 比如: watch可以进行异步操作

  3. 重要原则:

  1. 被Vue管理的函数, 最好写成普通函数, 这样this的指向才是vm或组件实例对象
  2. 所有不被Vue管理的函数, 最好写成箭头函数, 这样this的指向才是vm或组件实例对象
  3. (定时器的回调函数, ajax的回调函数, Promise的回调函数等..)
<div class="box">
    : <input type="text" v-model="name"> <br><br>
    : <input type="text" v-model="names"> <br><br>
    全名: <span>{{all}}</span>
</div>
new Vue({
    el: '.box',
    data: {
        name: '张',
        names: '三',
        all: '张-三'
    },
    watch: {
        name(value) {
            setTimeout(() => {
                this.all = value + '-' + this.names
            }, 1000)
        },
        names(value) {
            this.all = this.name + '-' + value
        }
    }
})

# 6. Vue绑定class样式 :class

  • :class="xxx" xxx可以是字符串、对象、数组
<div class="box">
    <!-- 1.绑定class样式: 字符串写法, 适用于 样式类名不确定, 需要动态指定 -->
    <div class="basic" :class="color" @click="show">{{name}}</div> <br>
    <!-- 2.数组写法, 适用于 要绑定的样式不确定, 名字也不确定 -->
    <div class="basic" :class="arr">{{name}}</div> <br>
    <!-- 3.对象写法, 适用于 要绑定的样式个数确定, 名字也确定 但要动态决定用不用 -->
    <div class="basic" :class="all">{{name}}</div>
</div>
new Vue({
    el: '.box',
    data: {
        name: '小城',
        color: 'normal',
        arr: ['n1', 'n2', 'n3'],
        all: {
            n1: false,
            n2: true
        }
    },
    methods: {
        show() {
            let arr = ['happy', 'sad', 'normal']
            let index = Math.floor(Math.random()*3)
            this.color = arr[index]
        }
    }
})

# 7. Vue绑定style样式 :style

  1. :style="{fontSize: xxx}" 其中xxx是动态值
  2. :style="[a, b]" 其中a,b是样式对象
<div class="box">
    <!-- 绑定style样式: 对象写法 -->
    <div class="basic" :style="{fontSize: size +'px'}">{{name}}</div> <br>
    <div class="basic" :style="fsize">{{name}}</div> <br>
    <!-- 绑定style样式: 数组写法 -->
    <div class="basic" :style="[fsize]">{{name}}</div> <br>
</div>
new Vue({
    el: '.box',
    data: {
        name: '小城',
        size: 20,
        fsize: {
            fontSize: '30px',
            backgroundColor: 'pink'
        }
    }
})

# 8. Vue条件渲染v-show/v-else-if/template模板

# 1. v-show写法: v-show="表达式"

  1. 表达式可以是布尔值、表达式、对象
  2. 适用于: 切换频率较高的场景
  3. 特点: 不展示的DOM元素只是隐藏了, 并未移除

# 2. v-if-else写法:

  1. v-if="表达式"
  2. v-else-if="表达式"
  3. v-else="表达式"
  4. v-if和template配合使用, template标签在页面是不会呈现的
  5. 表达式可以是布尔值、表达式、对象
  6. 适用于: 切换频率较低的场景
  7. 特点: 不展示的DOM元素直接移除
  8. 注意: v-if可以和v-else-if、v-else一起使用, 但要求结构不能被'打断'
<div class="box">
    <!-- v-show条件渲染可以是布尔值 也可以是表达式 -->
    <h1 v-show="true">{{name}}</h1>
    <h1 v-show="1 == 1">{{name}}</h1>
    <!-- v-show条件渲染也可以是对象 -->
    <h1 v-show="a">{{name}}</h1>
    <!-- v-if条件渲染可以是布尔值 也可以是表达式 -->
    <h1 v-if="false">{{name}}</h1>
    <h1 v-if="1 == 1">{{name}}</h1>
    <!-- 使用v-if条件渲染做交互 -->
    <h1>当前n的值是{{n}}</h1>
    <button @click="n++">点我让n+1</button>
    <div v-if="n == 1">1出来了</div>
    <div v-if="n == 2">2出来了</div>
    <div v-if="n == 3">3出来了</div>
    <!-- v-else和v-else-if的使用 -->
    <div v-if="n == 1">1出来了</div>
    <div v-else-if="n == 2">2出来了</div>
    <div v-else>没有了</div>
    <!-- v-if和template配合使用 -->
    <template v-if="n === 1">
        <div>1哈哈哈</div>
        <div>2哈哈哈</div>
        <div>3哈哈哈</div>
    </template>
</div>
new Vue({
    el: '.box',
    data: {
        name: '小城',
        a: true,
        n: 0
    }
})

# 9. Vue列表渲染v-for指令

  1. 用于展示列表数据
  2. 语法: v-for="(value, index) in xxx" :key="id"
  3. 可以遍历: 数组、对象、字符串、指定次数 后两个用的很少
<div class="box">
    <!-- 遍历数组 -->
    <h3>遍历数组</h3>
    <ul>
        <li v-for="(x, index) in arr" :key="index">{{x.name}} - {{x.age}}</li>
    </ul>
    <!-- 遍历对象 -->
    <h3>遍历对象-汽车信息</h3>
    <ul>
        <li v-for="(value, key) of obj" :key="key">{{value}} - {{key}}</li>
    </ul>
    <!-- 遍历字符串 -->
    <h3>遍历字符串</h3>
    <ul>
        <li v-for="(value, index) of str" :key="index">{{value}} - {{index}}</li>
    </ul>
    <!-- 遍历指定次数 -->
    <h3>遍历指定次数</h3>
    <ul>
        <li v-for="(value, index) of 5" :key="index">{{value}} - {{index}}</li>
    </ul>
</div>
new Vue({
    el: '.box',
    data: {
        arr: [
            {id: 1, name: '张三', age: 18},
            {id: 2, name: '李四', age: 19},
            {id: 3, name: '王五', age: 20}
        ],
        obj: {
            name: '奥迪',
            price: '50万',
            color: '黑色'
        },
        str: 'hello'
    }
})

# 10. Vue列表渲染v-for的key作用与原理

# 1. 虚拟DOM中key的作用

key是虚拟DOM对象的标识, 当数据发生变化时, Vue会根据新数据生成新的虚拟DOM

随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较(Diff算法)

# 2. 对比规则

(1) 旧虚拟DOM中找到了与新虚拟DOM相同的key:

若虚拟DOM中内容没变, 直接使用之前的真实DOM

若虚拟DOM中内容变了, 则生成新的真实DOM, 随后替换掉页面中之前的真实DOM

(2) 旧虚拟DOM中未找到与新虚拟DOM相同的key:

创建新的真实DOM, 随后渲染到页面

# 3. 用index作为key可能会引发的问题

1. 若对数据进行: 逆序添加、删除等破环顺序操作:

会产生没有必要的真实DOM ==> 界面效果没问题, 但效率低

2. 如果结构中还包含输入流的DOM:

会产生错误DOM更新 ==> 界面有问题

# 4. 开发中如何选择key?

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、学号等唯一值

2.如果不存在对数据的逆序添加、删除等破坏顺序的操作, 仅用于渲染列表、展示,

使用index作为key是没有问题的

# 5. 面试题: React、Vue中的key有什么作用? (key内部原理)

1. 虚拟DOM中key的作用:

key是虚拟DOM对象的标识, 当数据发生变化时, Vue会根据新数据生成新的虚拟DOM

随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较(Diff算法)

<div class="box">
    <ul>
        <li v-for="(x, index) in arr" :key="index">
            {{x.name}} - {{x.age}}
            <input type="text">
        </li>
    </ul>
    <button @click="add">添加一个老刘</button>
</div>
new Vue({
    el: '.box',
    data: {
        arr: [
            {id: 1, name: '张三', age: 18},
            {id: 2, name: '李四', age: 19},
            {id: 3, name: '王五', age: 20}
        ]
    },
    methods: {
        add() {
            let add = {id: 4, name: '老刘', age: 30}
            this.arr.unshift(add)
        }
    }
})

# 11. Vue的列表过滤

<div class="box">
    <ul>
        <li v-for="(x, index) in words" :key="index">
            {{x.name}} - {{x.age}} - {{x.sex}}
        </li>
    </ul>
    模糊搜索: <input type="text" placeholder="请输入名字" v-model="word">
</div>
new Vue({
    el: '.box',
    data: {
        word: '',
        arr: [
            {id: 1, name: '马冬梅', age: 18, sex: '女'},
            {id: 2, name: '周冬雨', age: 19, sex: '女'},
            {id: 3, name: '周杰伦', age: 20, sex: '男'},
            {id: 3, name: '温兆伦', age: 21, sex: '男'}
        ]
    },
    computed: {
        words() {
            console.log(this.word)
            return this.arr.filter((index) => {
                return index.name.indexOf(this.word) !== -1
            })
        }
    }
})
// new Vue({
//     el: '.box',
//     data: {
//         word: '',
//         words: [],
//         arr: [
//             {id: 1, name: '马冬梅', age: 18, sex: '女'},
//             {id: 2, name: '周冬雨', age: 19, sex: '女'},
//             {id: 3, name: '周杰伦', age: 20, sex: '男'},
//             {id: 3, name: '温兆伦', age: 21, sex: '男'}
//         ]
//     },
//     watch: {
//         // 1. watch的简写实现, 但有bug: 页面打开数据没有, 搜索正常
//         // word(value) {
//         //     console.log('word被改了', value)
//         //     this.words = this.arr.filter((index) => {
//         //         return index.name.indexOf(value) !== -1
//         //     })
//         // }
//         // 2. 使用watch的完整写法实现, immediate可以默认调用一次
//         word: {
//             immediate: true,
//             handler(value) {
//                 console.log('word被调用了', value)
//                 this.words = this.arr.filter((index) => {
//                     return index.name.indexOf(value) !== -1
//                 })
//             }
//         }
//     }
// })

# 12. Vue的列表过滤与列表排序

// 使用computed计算属性实现
<div class="box">
    <ul>
        <li v-for="(x, index) in words" :key="index">
            {{x.name}} - {{x.age}} - {{x.sex}}
        </li>
    </ul>
    模糊搜索: <input type="text" placeholder="请输入名字" v-model="word">
    <button @click="type = 2">年龄升序</button>
    <button @click="type = 1">年龄降序</button>
    <button @click="type = 0">原顺序</button>
</div>
new Vue({
    el: '.box',
    data: {
        word: '',
        type: 0, // 0原顺序 1降序 2升序
        arr: [
            {id: 1, name: '马冬梅', age: 31, sex: '女'},
            {id: 2, name: '周冬雨', age: 30, sex: '女'},
            {id: 3, name: '周杰伦', age: 20, sex: '男'},
            {id: 3, name: '温兆伦', age: 21, sex: '男'}
        ]
    },
    computed: {
        words() {
            console.log(this.word)
            let arr = this.arr.filter((index) => {
                return index.name.indexOf(this.word) !== -1
            })
            // 判断是否需要排序 使用.sort方法操作
            if (this.type) {
                arr.sort((a, b) => {
                    return this.type == 1 ? b.age-a.age : a.age-b.age
                })
            }
            return arr
        }
    }
})

# 13. data数据里的数组更新时的一个问题

// Vue数据层面变了, 但未检测到数据改变
<div class="box">
    <ul>
        <li v-for="(x, index) in arr" :key="index">
            {{x.name}} - {{x.age}} - {{x.sex}}
        </li>
    </ul>
    <button @click="news">更新马冬梅的信息</button>
</div>
new Vue({
    el: '.box',
    data: {
        arr: [
            {id: 1, name: '马冬梅', age: 31, sex: '女'},
            {id: 2, name: '周冬雨', age: 30, sex: '女'},
            {id: 3, name: '周杰伦', age: 20, sex: '男'},
            {id: 3, name: '温兆伦', age: 21, sex: '男'}
        ]
    },
    methods: {
        news() {
            // this.arr[0].name = '马老师'
            // this.arr[0].age = 50
            // this.arr[0].sex = '男'
            // 通过数组下标直接赋值是不行的
            // this.arr[0] = {id: 1, name: '马老师', age: 50, sex: '男'}
            // 这里使用数组.splice方法替换
            this.arr.splice(0, 1, {id: 1, name: '马老师', age: 50, sex: '男'})
        }
    }
})

# 14. Vue检测数据改变原理

  • Vue利用递归会一直在data属性里创建get/set
<div class="box">
    <h1>{{name}}</h1>
    <h1>{{names}}</h1>
</div>
new Vue({
    el: '.box',
    data: {
        name: '小城',
        names: '冲冲冲',
        a: {
            b: 'ok'
        },
        c: [1, 2]
    }
})

# 15. 模拟Vue对象数据监测

let data = {
    name: '尚硅谷',
    age: '北京'
}
console.log(data)

function Observer(obj) {
// 汇总对象所有属性形成一个数组
    let keys = Object.keys(obj)
    console.log(keys)
    keys.forEach((k) => {
        
// 此处this指向Observer实例对象
        Object.defineProperty(this,k, {
            // 数据代理 
            get() {
                return obj[k]
            },
            // 数据劫持
            set(value) {
                console.log('data属性被改了, 我去解析模板, 生成虚拟DOM了')
                obj[k] = value
            }
        })
    })
}
// 创建一个监视的实例对象, 用于监视data属性变化
let obs = new Observer(data)
// 准备一个vm实例对象 模拟Vue的_data
let vm = {}
vm._data = data = obs
console.log(obs)
console.log(vm)

// 死循环了
// Object.defineProperty(data, 'age', {
//     get() {
//         return data.age
//     },
//     set(val) {
//         data.age = val
//     }
// })

# 16. Vue.set方法的使用

  1. Vue.set方法: 向响应式对象添加属性
  2. 如果想给后期追加的属性添加响应式处理, 调用以下两个方法都可以
  3. 语法: Vue.set(目标对象, '属性名', '属性值')
  4. vm.$set(目标对象, 添加的属性名, 属性值)
  5. 注意对象不能为Vue实例 或者Vue实例的根数据对象
  6. 向响应式对象中添加一个property, 并确保这个新property同样是响应式的, 且触发视图更新
  7. 它必须用于向响应式对象上添加新property, 因为Vue无法探测普通的新增property
<div class="box">
    <h2>{{name}}</h2>
    <hr>
    <button @click="add">点我添加一个性别属性, 默认值为男</button>
    <h2>学生姓名: {{obj.name}}</h2>
    <h2 v-if="obj.sex">学生性别: {{obj.sex}}</h2>
    <h2>学生年龄: 真实 {{obj.ages.age1}} 对外 {{obj.ages.age2}}</h2>
    <h2>朋友们</h2>
    <ul>
        <li v-for="(x, index) in arr" :key="index">{{x.name}} - {{x.age}}</li>
    </ul>
</div>
new Vue({
    el: '.box',
    data: {
        name: '小城',
        obj: {
            name: '小明',
            // sex: '男', // undefined不显示页面
            ages: {
                age1: 10,
                age2: 20
            }
        },
        arr: [
            {name: '张三', age: 30},
            {name: '李四', age: 40}
        ]
    },
    methods: {
        add() {
            // Vue.set(this.obj, 'sex', '男')
            this.$set(this.obj, 'sex', '男')
        }
    }
})

# 17. 模拟Vue数组数据监测与原理

  • 通过数组下标修改数组中的元素, 默认情况是没有添加响应式处理的, 怎么解决?

# 1. 第一种方案

  1. 通过 Vue.set(数组对象, 下标, 值)
  2. 通过 vm.$set(数组对象, 下标, 值)

# 2. 第二种方案

通过这7个方法给数组添加响应式处理: push、pop、shift、unshift、splice、sort、reverse

Vue将被侦听的数组的变更方法进行了包裹, 所以它们也将会触发视图更新

<div class="box">
    <h2>{{name}}</h2>
    <hr>
    <button @click="add">点我添加一个性别属性, 默认值为男</button>
    <h2>学生姓名: {{obj.name}}</h2>
    <h2 v-if="obj.sex">学生性别: {{obj.sex}}</h2>
    <h2>学生年龄: 真实 {{obj.ages.age1}} 对外 {{obj.ages.age2}}</h2>
    <h2>朋友们</h2>
    <ul>
        <li v-for="(x, index) in arr" :key="index">{{x.name}} - {{x.age}}</li>
    </ul>
    <!-- 模拟Vue数组数据监测 -->
    <h2>爱好</h2>
    <ul>
        <li v-for="(x, index) in like" :key="index">{{x}}</li>
    </ul>
</div>
new Vue({
    el: '.box',
    data: {
        name: '小城',
        obj: {
            name: '小明',
            // sex: '男',
            ages: {
                age1: 10,
                age2: 20
            }
        },
        like: ['唱歌', '跳舞', '篮球'],
        arr: [
            {name: '张三', age: 30},
            {name: '李四', age: 40}
        ]
    },
    methods: {
        add() {
            // Vue.set(this.obj, 'sex', '男')
            this.$set(this.obj, 'sex', '男')
        }
    }
})

# 18. 总结Vue监测数据原理/对象/数组

# 1. Vue监测数据的原理: Vue会监视data中所有层次的数据

# 2. 如何监测对象中的数据?

通过setter实现监视, 且要在new Vue时就传入要监测的数据

(1) 对象中 后追加的属性, Vue默认不做响应式处理

(2) 如果给 后添加的属性做响应式, 请使用以下API:

Vue.set(目标对象, 添加的属性名, 属性值) 或

vm.$set(目标对象, 添加的属性名, 属性

# 3. 如何监测数组中的数据?

通过包裹数组更新元素的方法实现, 本质就是做了两件事:

(1) 调用原生对应的JS方法对数组进行更新

(2) 重新解析模板, 进而更新页面

# 4. 在Vue修改数组中的某个元素一定要用以下方法:

使用这些API: push、pop、shift、unshift、splice、sort、reverse

Vue.set() 或 vm.$set()

注意: Vue.set 和 vm.$set 不能给vm或vm的根数据对象 添加属性 !!!

<div class="box">
    <h3>姓名: {{xs.name}}</h3>
    <h3>年龄: {{xs.age}}</h3>
    <h3 v-if="xs.sex">性别: {{xs.sex}}</h3>
    <h3>爱好: </h3>
    <ul>
        <li v-for="(x, index) in xs.like" :key="index">{{x}}</li>
    </ul>
    <h3>朋友们: </h3>
    <ul>
        <li v-for="(x, index) in xs.arr" :key="index">{{x.name}} - {{x.age}}</li>
    </ul>
    <button @click="xs.age++">年龄+1</button> <br>
    <button @click="addName">添加性别属性: 默认值:</button> <br>
    <button @click="xs.sex = '女'">修改性别属性:</button> <br>
    <button @click="addArr">在列表首位添加一个朋友</button> <br>
    <button @click="addArrs">修改第一个朋友名字为: 爱坤</button> <br>
    <button @click="addLike">添加一个爱好</button> <br>
    <button @click="addLikes">修改第一个爱好为: 开车</button> <br>
    <button @click="addFilter">过滤掉爱好中的篮球</button>
</div>
new Vue({
    el: '.box',
    data: {
        xs: {
            name: '小城',
            age: 18,
            like: ['唱歌', '跳舞', '篮球'],
            arr: [
                { name: '张三', age: 30 },
                { name: '李四', age: 40 }
            ]
        }
    },
    methods: {
        addName() {
            Vue.set(this.xs, 'sex', '男')
        },
        addArr() {
            this.xs.arr.unshift({name: '蔡徐坤', age: 20})
        },
        addArrs() {
            // Vue.set(this.xs.arr[0], 'name', '爱坤')
            this.xs.arr[0].name = '爱坤'
            this.xs.arr[0].age = 10
        },
        addLike() {
            this.xs.like.push('学习')
        },
        addLikes() {
            // this.xs.like.splice(0, 1, '开车')
            // Vue.set(this.xs.like, 0, '开车')
            this.$set(this.xs.like, 0, '开车')
        },
        addFilter() {
            this.xs.like = this.xs.like.filter((x) => {
                return x !== '篮球'
            })
        }
    }
})

# 19. Vue的收集表单数据/v-model/lazy/number/trim

  1. 若: input type="text" 则v-model收集的是value值, 用户输入的就是value值
  2. 若: input type="radio" 则v-model收集的是value值, 且要给标签配置value值
  3. 若: input type="checked"
  • (1) 没有配置input的value属性, 那么收集的就是checked(勾选true/未勾选false)
  • (2) 配置input的value属性
  • v-model的初始值是非数组, 那么收集的就是checked(勾选true/未勾选false)
  • v-model的初始值是数组, 那么收集的就是value组成的数组

备注: v-model的三个修饰符:

lazy: 失去焦点再收集数据

number: 输入字符串转换为number类型

trim: 空格过滤

<div class="box">
    <form action="" @submit.prevent="arr">
        账号: <input type="text" v-model.trim="obj.user"> <br><br>
        密码: <input type="password" v-model="obj.pass"> <br><br>
        年龄: <input type="number" v-model.number="obj.age"> <br><br>
        性别: 
        : <input type="radio" name="sex" v-model="obj.sex" value="nan">
        : <input type="radio" name="sex" v-model="obj.sex" value="nv"> <br><br>
        爱好: 
        学习<input type="checkbox" v-model="obj.like" value="xx">
        唱歌<input type="checkbox" v-model="obj.like" value="cg">
        篮球<input type="checkbox" v-model="obj.like" value="lq"> <br><br>
        所属校区: 
        <select v-model="obj.city">
            <option value="">请选择校区</option>
            <option value="bj">北京</option>
            <option value="ss">上海</option>
            <option value="sz">深圳</option>
            <option value="wh">武汉</option>
        </select> <br><br>
        其他信息: <textarea v-model.lazy="obj.text"></textarea> <br><br>
        <input type="checkbox" v-model="obj.check">阅读并接受<a href="">《用户协议》</a>
        <button>提交</button>
    </form>
</div>
new Vue({
    el: '.box',
    data: {
        obj: {
            user: '',
            pass: '',
            age: '',
            sex: 'nan',
            like: [],
            city: 'ss',
            text: '',
            check: ''  
        }
    },
    methods: {
        arr() {
            console.log(this._data.obj)
            console.log(JSON.stringify(this._data.obj))
        }
    }
})

# 20. Vue的过滤器/filter/dayjs库

过滤器定义: 对要显示的数据进行特殊格式化后再显示(适应于一些简单逻辑处理)

# 过滤器语法:

  1. 注册过滤器: Vue.filter(name, function) 或 new Vue{filters: {}}
  2. 使用过滤器: {xxx | 过滤器名} 或 v-bind:属性 = 'xxx' | 过滤器名

# 备注:

  1. 过滤器也可以接收额外参数, 多个过滤器也可以串联
  2. 并没有改变原本的数据, 是产生新的对应数据
  3. 分全局过滤器、局部过滤器
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.7/dayjs.min.js"></script>
<div class="box">
    <h2>显示格式化后的时间</h2>
    <h2>{{time}}</h2>
    <!-- 计算属性实现 -->
    <h2>计算后的时间: {{times}}</h2>
    <!-- methods方法实现 -->
    <h2>计算后的时间: {{times1()}}</h2>
    <!-- Vue过滤器实现 -->
    <h2>计算后的时间: {{time | formater}}</h2>
    <!-- Vue过滤器实现(传参) -->
    <h2>计算后的时间: {{time | formater('YYYY-MM-DD')}}</h2>
    <!-- Vue过滤器实现(传参 + 过滤器串联) -->
    <h2>计算后的时间: {{time | formater('YYYY-MM-DD') | myslice}}</h2>
    <!-- Vue过滤器 应用在v-bind上(很少) -->
    <h2 :value="name | myslice">尚硅谷</h2>
</div>
<div class="box1">
    <!-- Vue全局过滤器实现 (传参 + 过滤器串联) -->
    <h2>计算后的时间: {{name | myslices}}</h2>
</div>
// 配置全局过滤器
Vue.filter('myslices', function (value) {
    return value.slice(0, 4)
})
new Vue({
    el: '.box',
    data: {
        time: 1687892086472,
        name: '你好, 尚硅谷'
    },
    computed: {
        times() {
            return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
        }
    },
    methods: {
        times1() {
            return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
        }
    },
    filters: {
        formater(value, str = 'YYYY年MM月DD日 HH:mm:ss') {
            console.log(value)
            return dayjs(value).format(str)
        },
        myslice(value) {
            return value.slice(0, 4)
        }
    }
})
new Vue({
    el: '.box1',
    data: {
        name: '小城故事, 你好'
    }
})