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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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. 监视属性的两种写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<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时根据数据的具体结构, 决定是否采用深度监视
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<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才能简写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<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的回调函数等..)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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可以是字符串、对象、数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<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是样式对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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一起使用, 但要求结构不能被’打断’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<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. 可以遍历: 数组、对象、字符串、指定次数 后两个用的很少
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<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算法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<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的列表过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<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的列表过滤与列表排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 使用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数据里的数组更新时的一个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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对象数据监测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<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将被侦听的数组的变更方法进行了包裹, 所以它们也将会触发视图更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<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的根数据对象 添加属性 !!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<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: 空格过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<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. 分全局过滤器、局部过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<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: '小城故事, 你好'
}
})