响应式渲染
Vue的架构模式:MVVM - 双向数据绑定
MVVM(Model-View-ViewModel)
表示逻辑与用户界面(UI)清晰分离。这种分离使得应用程序更易于测试、维护和演变,同时显著提高代码重用机会。
在MVVM中,Model(模型)代表数据模型,View(视图)代表用户界面,而ViewModel则是这两者之间的连接者,它包含了视图所需要的表示逻辑。ViewModel负责将Model中的数据转化为View所需的格式,并监听Model的变化以更新View。同时,ViewModel也提供了命令或方法供View调用,以改变Model的状态。
与MVVM不同,MVC(Model-View-Controller)模式也是用于划分应用程序逻辑和用户界面交互的一种设计模式。在MVC中,Model同样负责数据的处理,View负责数据的展示,而Controller则负责接收用户的输入,并调用Model和View以完成用户的请求。MVC模式强调将业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
MVVM和MVC的主要区别:
- 数据绑定方式:MVVM采用双向数据绑定,即当Model中的数据发生变化时,View会自动更新;同时,当View中的数据发生变化时,Model也会相应更新。而MVC则采用单向数据绑定,数据流动方向是从Model到View,通过Controller进行控制。
- 关注点分离:虽然MVC和MVVM都试图实现关注点分离,但MVVM在View和Model之间引入了ViewModel,使得View与Model之间的直接联系更少,进一步提高了关注点分离的程度。
- 适用场景:MVC模式最初生根于服务器端的Web开发,后来渐渐能够胜任客户端Web开发,满足其复杂性和丰富性。而MVVM则更多地应用于前端开发中,特别是当使用现代前端框架(如Vue.js或Angular)时。
ViewModel在MVVM设计模式中的好处:
- 关注点分离:ViewModel负责将Model(模型)中的数据转换为View(视图)所需的格式,并监听Model的变化以更新View。这种分离使得业务逻辑与表示逻辑(即UI逻辑)之间解耦,使得代码更易于理解和维护。开发者可以专注于实现业务逻辑,而不需要过多关心UI的细节。
- 双向数据绑定:通过ViewModel,实现了Model和View之间的双向数据绑定。这意味着当Model中的数据发生变化时,View会自动更新;同时,当用户在View中做出更改时,这些更改也会自动反映到Model中。这种自动更新机制极大地简化了数据同步的复杂性,提高了开发效率。
- 提高可测试性:由于ViewModel与View和Model之间的解耦,开发者可以更容易地对ViewModel进行单元测试。这有助于确保ViewModel的逻辑正确性,减少潜在的错误和bug。
- 增强代码复用性:ViewModel通常包含表示逻辑,这些逻辑可以在多个视图之间共享和复用。例如,相同的ViewModel可以被用于不同的视图或组件,只要它们显示相同的数据和交互逻辑。这减少了代码的重复,提高了代码的重用性。
- 易于维护:由于MVVM模式中的关注点分离和清晰的结构,当业务逻辑或UI需求发生变化时,开发者可以更轻松地定位和修改相应的代码。这使得应用程序的维护变得更加容易和高效。
01-模板语法
插值
<p>{{ message }}</p>
指令
v-text和v-html
v-text
指令用于更新元素的 textContent
。它会根据表达式的内容来更新元素的文本内容。如果表达式返回 null
、undefined
或空字符串,则元素内容会被清空。v-html
指令用于更新元素的 innerHTML
。v-html
解析 HTML 字符串,并将解析后的内容插入到元素中。
<template>
<div>
<p v-text="message"></p>
<p v-html="rawHtml"></p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!',
rawHtml: '<span style="color: red;">Hello Vue!</span>'
}
}
}
</script>
注意:使用 v-html
时要小心,因为它可能导致 XSS(跨站脚本)攻击,特别是当你插入的内容来自不可信的源时。确保你完全信任并控制要插入的 HTML 内容。最好是尽量避免使用v-html
当然在使用的过程中疑惑v-text
和基础的{{ }}
插值方式有什么区别吗?
- 渲染方式:
v-text
:是一个指令,它会替换元素内的所有内容。当v-text
绑定的数据发生变化时,它会直接更新元素的textContent
。{{ }}
:是一种语法糖,它可以将数据解析为纯文本并插入到模板中。当绑定的数据发生变化时,插值表达式的内容也会自动更新。
- 屏幕闪硕问题:
- 在渲染大量数据时,使用
{{ }}
插值可能会导致屏幕闪动,这是因为插值表达式在数据更新时会被临时替换为原始的大括号({{ }}
),然后再更新为新的值。 - 使用
v-text
可以避免这个问题,因为它会一次性替换元素的内容,不会显示中间状态。
- 在渲染大量数据时,使用
- 使用场景:
v-text
更适合于需要完全替换元素内容的场景。{{ }}
插值则更灵活,可以用于插入文本到元素的任何位置,而不仅仅是替换整个内容。此外,它还可以与其他文本或HTML混合使用。
带有 v- 前缀的特殊属性
- v-bind 动态绑定HTML属性 =>
:src
- v-if 动态创建/删除
- v-show 动态显示/隐藏
- v-on:click 绑定事件 =>
@click
- v-for 遍历
- v-model 双向绑定表单
02-条件渲染
<template>
<div>
<div v-if="score >= 90">Excellent</div>
<div v-else-if="score >= 60">Good</div>
<div v-else>Poor</div>
</div>
</template>
<script>
export default {
data() {
return {
score: 85
}
}
}
</script>
template 就是一个包装元素, 不会真正创建在页面上。
03-列表渲染
<template>
<div>
<ul>
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
items: ['Apple', 'Banana', 'Cherry']
}
}
}
</script>
- 用
in
和of
没有区别 - 使用了
:key
绑定来为每个循环的元素提供一个唯一的键,这有助于 Vue 更高效地更新 DOM。
04-事件处理
<button @click="handleAdd1()">add-1-函数表达式</button>
加小括号传入自定义形参
<input type="text" @input="handleInput"/>
handleInput(evt) {
console.log("input", evt.target.value)
},
不加小括号能获取事件对象,evt.target.value
拿到input框内的值
<button @click="handleAdd1($event,1,2,3)">add-1-函数表达式</button>
handleAdd1(evt, a, b, c) {
console.log(evt, a, b, c)
this.count++
},
同时传入形参并获取事件对象
事件修饰符
修饰符包括:
.prevent
:阻止默认事件的触发。.stop
:阻止事件冒泡。.once
:事件只触发一次,之后移除监听器。.capture
:使用事件捕获模式,即从外部元素开始触发事件。.self
:只触发自己范围内的事件。.passive
用于告诉浏览器不要阻止事件的默认行为。
<ul @click.self="handleUlClick"> // 点自己本身才触发,点孩子不触发
<li @click.stop="handleLiClick">1111</li> // 阻止事件冒泡。
<li @click="handleLiClick">2222</li>
<li @click.once="handleLiClick">3333</li> // 只有效一次
</ul>
<a href="http://www.baidu.com" @click.prevent>跳转</a> // 阻拦跳转
.passive
修饰符的主要目的是提高性能。当我们在事件处理程序中调用preventDefault
时,浏览器会等待事件处理程序执行完毕后才能知道是否应该阻止默认行为。这可能导致浏览器无法立即开始某些操作,比如滚动优化。通过使用.passive
修饰符,我们告诉浏览器:“我知道这个事件处理程序不会阻止默认行为,所以你可以立即开始执行相关操作。”
为什么要用.passive
修饰符呢?
因为在滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询prevent
会使滑动卡顿。我们通过passive
将内核线程查询跳过,可以大大提升滑动的流畅度。
举个例子,假设我们有一个滚动事件监听器,并且我们知道这个监听器不会调用preventDefault
。我们可以使用.passive
修饰符来优化滚动性能:
<div v-on:scroll.passive="handleScroll">滚动内容</div>
注意:.passive
修饰符只能用于某些特定的事件类型,如滚动事件(scroll
)、触摸事件(touchstart
、touchmove
)等,因为这些事件类型通常与浏览器默认行为(如滚动、缩放)相关。对于其他事件类型,使用.passive
修饰符可能不会有任何效果。
按键修饰符
按键修饰符则允许为v-on
在监听键盘事件时添加特定的按键条件。例如,如果你想在用户按下回车键时触发某个方法,你可以这样写:<input @keyup.enter="handleEnter">
。这样,只有当用户按下回车键时,handleEnter
方法才会被触发。
<input type="text" @keyup.enter.ctrl="handleKeyup"/> // 监听当用户同时按下Ctrl键和Enter键时触发的事件
<input type="text" @keyup.65="handleKeyup"/> // 监听当用户释放A键时触发的事件
<!-- .esc , .up .down .left .right ,.space .ctrl .shift .delete -->
Vue.js中的按键修饰符用于监听特定的按键事件。以下是一些常用的按键修饰符:
.enter
:监听回车键(Enter)的按下事件。.tab
:监听Tab键的按下事件。需要注意的是,.tab
修饰符必须配合keydown
事件使用。.delete
(或.del
):监听删除键(Delete或Backspace)的按下事件。.esc
:监听Escape键的按下事件。.space
:监听空格键的按下事件。.up
、.down
、.left
、.right
:分别监听上、下、左、右箭头键的按下事件。
Vue允许自定义按键修饰符,通过Vue的全局配置对象config
来进行按键修饰符的自定义。语法规则是:Vue.config.keyCodes.按键修饰符的名字 = 键值
。
05-表单绑定
Vue.js提供了v-model
指令来实现表单元素的双向绑定。v-model
指令在表单<input>
、<textarea>
及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
下面是一些使用v-model
进行表单绑定的示例:
文本输入框
<template>
<div>
<input v-model="message" placeholder="输入一些文字">
<p>你输入的是: {{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
}
}
</script>
单选按钮
<template>
<div>
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
</template>
<script>
export default {
data() {
return {
picked: ''
}
}
}
</script>
复选框
对于复选框,可以使用v-model
绑定到一个数组,以便存储多个选中的值:
<template>
<div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
</template>
<script>
export default {
data() {
return {
checkedNames: []
}
}
}
</script>
选择框(单选)
<template>
<div>
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
</template>
<script>
export default {
data() {
return {
selected: ''
}
}
}
</script>
选择框(多选)
<template>
<div>
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
</template>
<script>
export default {
data() {
return {
selected: []
}
}
}
</script>
表单修饰符
.lazy
:在用户填完信息并且光标离开标签后,才会将值赋给value
,即在change
事件之后再进行信息同步。.trim
:自动过滤用户输入的首空格字符,而中间的空格不会过滤。.number
:自动将用户的输入值转为数值类型,但如果这个值无法被parseFloat
解析,则会返回原来的值。
06-计算属性
watch method computed区别
属性/方法 | watch | computed | method |
---|---|---|---|
作用 | 监听数据变化并执行回调函数 | 基于其他数据计算属性并缓存结果 | 定义可复用的逻辑方法 |
使用场景 | 数据变化时执行副作用操作 | 需要动态计算并缓存结果的属性 | 定义逻辑操作,如事件处理、数据验证等 |
缓存性 | 不支持缓存,数据变化时直接触发 | 支持缓存,只有当依赖数据变化时才会重新计算 | 无缓存,每次调用都执行方法体 |
异步操作 | 支持 | 不支持 | 支持 |
调用方式 | 自动触发回调函数 | 在模板中直接使用,无需调用 | 在模板中通过事件绑定或其他方式调用 |
返回值 | 无特定返回值,执行副作用操作 | 返回计算属性的结果 | 根据方法逻辑返回任意值 |
依赖 | 依赖于被观察的数据属性 | 依赖于其他数据属性进行计算 | 不依赖于特定数据属性,可以独立执行 |
总结来说,watch
用于监听数据变化并执行回调,method
用于定义可复用的逻辑方法,而computed
则用于基于其他数据属性进行计算并缓存结果。