插值表达
- {{msg}}
- v-bind / :
- Vue 实例内通过 this.msg 获取
<div id="app">
<!-- 文本 -->
<div>{{msg}}</div>
<!-- attribute -->
<!-- 指令 v-bind -->
<div v-bind:test="test">{{msg}}</div>
<!-- 简写 : -->
<div :test="test">{{msg}}</div>
<!-- 表达式 -->
<!-- 运算 -->
<div :test="test+'123123'">{{msg+"123123"}}</div>
<!-- 三目运算 -->
<div :test="true?test:''">{{true?msg:""}}</div>
</div>
const app = new Vue({
el: "#app",
data: {
msg: "hello world",
test: "vue"
}
});
事件处理
- v-on:click / @click 添加事件
- methods 储存事件
- .once 修饰符 只执行一次
<div id="app">
<!-- 指令 v-on:click -->
<button v-on:click="handleClick">按钮</button>
<!-- 简写 @click -->
<button @click="handleClick">按钮</button>
<!-- 传参 -->
<button @click="handleOptions(1, $event)">按钮</button>
<!-- .once -->
<button @click.once="handleOnce">按钮</button>
</div>
const app = new Vue({
el: '#app',
methods: {
// e 对应 MouseEvent
handleClick(e) {
console.log(e);
},
handleOptions(num, e) {
console.log(num, e)
},
handleOnce() {
console.log("只生效一次")
}
}
});
计算属性
-
为了解决 {{msg + "123" + "456" + "789"}} 表达式繁琐,破坏可读性
-
components
-
computed 和 methods 区别是什么?
-
更清晰的表达
-
缓存
- 以下呆码 reverseMsg1 、 reverseMsg2 都可实现 reverseMsg 效果
- 所依赖响应式参数 msg 改变时才发生改变
- 一般情况下用 computed 性能更优
- app.reverseMsg1 -> "dlrow olleh"
- app.reverseMsg2() -> 222 "dlrow olleh" 会重新执行函数
- 因为 computed 会利用缓存对性能进行优化,使得重复读取 reverseMsg1 时不会重复计算,而 methods 则会重复执行降低性能
-
-
如何写好呆码
- 表达好呆码的意图(命名,可读性)
- 写测试
- 减少重复
<div id="app">
<!-- data -->
<div>{{msg.split("").reverse().join("")}}</div>
<!-- components -->
<div>{{reverseMsg1}}</div>
<div>{{reverseMsg1}}</div>
<!-- methods -->
<div>{{reverseMsg2()}}</div>
<div>{{reverseMsg2()}}</div>
</div>
const app = new Vue({
el: '#app',
data: {
msg: 'hello world'
},
computed: {
reverseMsg1() {
console.log(111);
return this.msg.split('').reverse().join('');
}
},
methods: {
reverseMsg2() {
console.log(222);
return this.msg.split('').reverse().join('');
}
}
});
watch
-
观察依赖参数,当依赖参数改变时,进行处理
-
watch 与 components 区别是什么?
- watch 观察 一个依赖 更新对应 多个值: 1 对 多 的关系
- components 多个依赖其中一个 更新对应 一个值: 多 对 1 的关系
-
可写成对象形式
- handler 为执行事件
- immediate 为 true 时,立刻执行
-
当观察的依赖为 对象 时,默认不会观察对象深度,如需观察加上 deep: true
-
需要观察 对象的某个key 时,可通过 "obj.key" 进行观察
<div id="app">
<div>{{msg}}</div>
<div>{{msg1}}</div>
<div>{{msg2}}</div>
<div>{{msg3}}</div>
<hr />
<div>{{info.a}}</div>
<div>{{info.b}}</div>
<hr />
<button @click="handleClick1">改变msg</button>
<button @click="handleClick2">改变info.a</button>
<button @click="handleClick3">改变info.b</button>
</div>
const app = new Vue({
el: '#app',
data: {
msg: 'hello world',
msg1: '',
msg2: '',
msg3: '',
info: {
a: 'infoA',
b: 'infoB'
}
},
watch: {
// 写法一
msg(newValue, oldValue) {
console.log(newValue, oldValue);
this.msg1 = newValue + '1';
this.msg2 = newValue + '2';
this.msg3 = newValue + '3';
},
// 写法二
msg: {
handler(newValue, oldValue) {
console.log(newValue, oldValue);
this.msg1 = newValue + '1';
this.msg2 = newValue + '2';
this.msg3 = newValue + '3';
},
immediate: true // 为 true 时,立刻执行
},
// 对象
info: {
handler(newValue, oldValue) {
console.log(newValue, oldValue);
},
deep: true // 为 true 时,观察对象深度
},
// 只观察对象某个 key 时
// 观看效果需要把上面对 info 的观察进行注释
'info.a': {
handler(newValue, oldValue) {
console.log(newValue, oldValue);
}
}
},
methods: {
handleClick1() {
this.msg = 'watch'
},
handleClick2() {
this.info.a = 'infoAWatch'
},
handleClick3() {
this.info.b = 'infoBWatch'
}
},
});
条件渲染
- 条件的处理与 js 无异,无非就是 if elseif else,不过在 Vue 里我们需要加上 v- ,不过呢,Vue 还有一个 v-show
- v-if vs v-show
- v-if 在被隐藏的时候会留下一个 <!----> 注释
- v-if 是真正的条件渲染,它会确保在切换过程中,条件块内的事件监听器和子组件适当的被销毁和重建
- v-if 也是懒惰的,如果在初次渲染中条件为 false 时,他会什么都不做,知道条件第一次为 true 时,才会开始渲染
- v-show 不管条件是什么,元素都会进行渲染,因为他只是简单的基于 css的display 切换
- 一般情况下,v-if 有更高的切换开销,v-show 有更高的初次渲染开销
- 如果代码块需要频繁的切换,使用 v-show 会比较好
- 如果代码块很少进行改变,那么使用 v-if 会更好
<div id="app">
<div v-if="age === 18">花一样的年龄</div>
<div v-else-if="age > 18">成年人</div>
<div v-else>未成年</div>
<div v-show="true">show</div>
</div>
const app = new Vue({
el: '#app',
data: {
age: 18
}
});
循环
- v-for: (item,index) in arrList | (val,key,index) in objList
- Vue 统一了处理接口 in ,没有 js 这么多循环方法
- 优化策略 key
- 非强制,不写会有小警告,不影响使用
- 为了 diff 优化,使更新DOM的时候性能更好
- key 不能重复,重复则会出现性能问题,也会发生一些状态 bug
- 最好不使用 index 值,会造成重复 有空写个bug出来
<div id="app">
<ul>
// 对象
<li v-for="(val,key,index) in objList" :key="'objList'+val.id">index:{{index}} -- key:{{key}} -- name:{{val.name}} -- age:{{val.age}}</li>
<hr />
// 数组
<li v-for="(item,index) in arrList" :key="'arrList'+item.id">index:{{index}} -- name:{{item.name}} -- age:{{item.age}}</li>
</ul>
</div>
const app = new Vue({
el: '#app',
data: {
// 对象
objList: {
a: {
id: 1,
name: '小黑',
age: 18
},
b: {
id: 2,
name: '小白',
age: 18
}
},
// 数组
arrList: [
{
id: 1,
name: '小黑',
age: 18
}, {
id: 2,
name: '小白',
age: 24
}
]
}
});
class & style
- class 可通过
:class绑定- 对象:key 为 className ,通过 value: true | false 控制是否有 class
- 数组:可使用 三元表达式 控制是否有 class
- 数组对象:两者结合
- style 可通过
:style绑定- 对象:key 需要使用 小驼峰命名法
- 数组对象
.red {
color: red;
}
.size {
font-size: 50px;
}
<div id="app">
<div :class="classes">css</div>
<div :style="styleInfo">style</div>
</div>
const app = new Vue({
el: '#app',
data: {
// 对象
classes: {
red: true,
size: true,
},
// 数组
classes: [
true ? 'red' : '',
{ size: true }
],
// 对象
styleInfo: {
color: 'red',
fontSize: '50px'
},
// 数组
styleInfo: [{
color: 'blue'
}, {
fontSize: '50px'
}]
}
});
input表单
- 使用 methods 与数据进行绑定
<div id="app">
<input type="text" @input="handleInput" />
<div>{{msg}}</div>
<input type="checkbox" @input="handleChange" />
<div>{{isCheckBox}}</div>
</div>
const app = new Vue({
el: '#app',
data: {
msg: '',
isCheckBox: false
},
methods: {
handleInput(e) {
console.log(e.target.value);
this.msg = e.target.value;
},
handleChange(e) {
this.isCheckBox = e.target.checked;
}
}
});
- 我们发现使用 methods 会比较麻烦
- 需要 监听 input => 处理事件监听 => 拿到 input 的值 => 进行数据的更新 => 更新视图
- 但是我们实际工作中这种需求场景比较多,使得代码更加繁琐
- 这个时候 Vue 就给我们带来了一个内置的语法糖
v-model- 它可以直接写入我们需要绑定的值,即可完成我们上面的一系列操作
v-model看起来像是一个 双向数据流,实际上只是内置语法糖,简化了写法v-model在内部为不同的输入元素使用不同的 property 并抛出不同的事件- text 和 textarea 元素使用
valueproperty 和input事件 - checkbox 和 radio 使用
checkedproperty 和change事件 - select 字段将
value作为 prop 并将change作为事件
- text 和 textarea 元素使用
- 可通过修饰符
.number转换成number类型,下面案例通过watch观察他的类型 - 除此外还有
.lazy.trim修饰符
<div id="app">
<input type="text" v-model="msg" />
<div>{{msg}}</div>
<input type="number" v-model.number="num" />
<div>{{num}}</div>
<input type="checkbox" v-model="isCheckBox" />
<div>{{isCheckBox}}</div>
</div>
const app = new Vue({
el: '#app',
data: {
msg: '',
isCheckBox: false,
num: ''
},
watch: {
num(newValue, oldValue) {
console.log(typeof newValue);
}
},
});
小示例
<div id="app">
<ul>
<li v-for="(product,index) in products" :key="index">
{{product.name}} -- {{product.count}}
<span v-if="product.count === 0">卖没辣</span>
<span v-else>还有货</span>
<button @click="product.count++">+1</button>
<button @click="--product.count<0?product.count=0:''">-1</button>
</li>
</ul>
总数:{{totalCount}}
</div>
const app = new Vue({
el: '#app',
data: {
products: [{
count: 1,
name: '苹果'
}, {
count: 0,
name: '香蕉'
}, {
count: 1,
name: '雪梨'
}]
},
computed: {
totalCount() {
return this.products.reduce((total, item) => {
return total + item.count
}, 0)
}
}
});