Vue3中文文档收获
基础
一.应用&组件实例
1.1.根组件
constRootComponent={/* 选项 */}
constapp=Vue.createApp(RootComponent)
constvm=app.mount('#app')
1.2.组件实例property
1.3.生命周期钩子
1.4.生命周期图示
二. 模板语法
2.1.插值
2.2.指令
2.3.缩写
2.4.注意事项:
三.Data Property 和方法
3.1.data Property
3.2.方法
四. 计算属性和监听器
4.1.计算属性
基本例子
写实例
计算属性缓存vs 方法
计算属性在运行之后会有缓存,当值不发生改变时,会只执行一次
和methods不一样
计算属性的setter
可以用来改变计算属性里面所用到的值,
4.2.侦听器
计算属性 vs 侦听器
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
除了 watch 选项之外,你还可以使用命令式的 vm.$watch API。
五. Class 与 Style 绑定
5.1.绑定 HTML Class
对象语法
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
数组语法
<div:class="[isActive ? activeClass : '', errorClass]"></div>
//当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法:
<div:class="[{ active: isActive }, errorClass]"></div>
在组件上使用
<divid="app">
<my-componentclass="baz boo"></my-component>
</div>
//结果是<pclass="foo bar baz boo">Hi</p>
//也可以如下使用
<my-component:class="{ active: isActive }"></my-component>
<script>
constapp=Vue.createApp({})
app.component('my-component', {
template:`<p class="foo bar">Hi!</p>`
})
</script>
//如果你的组件有多个根元素,你需要定义哪些部分将接收这个类。可以使用 $attrs 组件属性执行此操作:
<script>
constapp=Vue.createApp({})
app.component('my-component', {
template:`
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
`
})
</script>
5.2.绑定内联样式
对象语法
<div:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<script>
constapp=Vue.createApp({
data() {
return{
activeColor:'red',
fontSize:30
}
}
})
</script>
//如下形式比较好
<div:style="styleObject"></div>
<script>
constapp=Vue.createApp({
data() {
return{
styleObject: {
color:'red',
fontSize:'13px'
}
}
}
})
</script>
! ! !对象语法常常结合返回对象的计算属性使用
数组语法
:style` 的数组语法可以将多个样式对象应用到同一个元素上:
<div:style="[baseStyles, overridingStyles]"></div>
自动添加前缀
在 :style 中使用需要 (浏览器引擎前缀) vendor prefixes 的 CSS property 时,如 transform,Vue 将自动侦测并添加相应的前缀。
多重值
可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于 提供多个带前缀的值,例如:
<div:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
六. 条件渲染
6.1.v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
<h1v-if="awesome">Vue is awesome!</h1>
也可以用 v-else 添加一个“else 块”:
<h1v-if="awesome">Vue is awesome!</h1>
<h1v-else>Oh no 😢</h1>
在 <template> 元素上使用 v-if 条件渲染分组
因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。
v-else
<divv-if="Math.random() > 0.5">
Now you see me
</div>
<divv-else>
Now you don't
</div>
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-else-if
<divv-if="type === 'A'">
A
</div>
<divv-else-if="type === 'B'">
B
</div>
<divv-else-if="type === 'C'">
C
</div>
<divv-else>
Not A/B/C
</div>
类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
6.2.v-show
<h1v-show="ok">Hello!</h1>
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。
注意,v-show 不支持 <template> 元素,也不支持 v-else。
6.3.v-if vs v-show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
6.4.v-if 与 v-for 一起使用
提示
不推荐同时使用 v-if 和 v-for。请查阅风格指南以获取更多信息。
当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级。请查阅列表渲染指南以获取详细信息。
七.列表渲染
7.1.用v-for把一个数组对应为一组元素
<ulid="array-rendering">
<liv-for="(item,index) in/of items">
{{ item.message }} {{index}}
</li>
</ul>
<script>
Vue.createApp({
data() {
return{
items: [{message:'Foo'}, {message:'Bar'}]
}
}
}).mount('#array-rendering')
</script>
7.2.在v-for里使用对象
<ulid="v-for-object"class="demo">
<liv-for="value in myObject">
{{ value }}
</li>
</ul>
<script>
Vue.createApp({
data() {
return{
myObject: {
title:'How to do lists in Vue',
author:'Jane Doe',
publishedAt:'2016-04-10'
}
}
}
}).mount('#v-for-object')
</script>
//也可以提供第二个参数为属性的key值
<liv-for="(value, name) in myObject">
{{ name }}: {{ value }}
</li>
//第三个参数为索引值,案例如下:
<liv-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>
结果为:
7.3.维护状态
7.4.数组更新检测
变更方法
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
替换数组
利用 filter()、concat()和slice()进行数组的替换,它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组
example1.items=example1.items.filter(item=>item.message.match(/Foo/))
7.5.显示过滤/排序后的结果
<liv-for="n in evenNumbers">{{n}}</li>
computed: {
evenNumbers() {无参
returnthis.numbers.filter(number=>number%2===0)
}
}
//如果不支持的话,则用methords(比如在嵌套v-for中就不支持计算属性)
<ulv-for="numbers in sets">
<liv-for="n in even(numbers)">{{n}}</li>
</ul>
methods: {
even(numbers) {//有参
returnnumbers.filter(number=>number%2===0)
}
}
7.6.在v-for里使用值的范围
//v-for支持证书
<divid="range"class="demo">
<spanv-for="n in 10">{{ n }}</span>
</div>
7.7.在 <template> 中使用 v-for
<ul>
<templatev-for="item in items">
<li>{{ item.msg }}</li>
<liclass="divider"role="presentation"></li>
</template>
</ul>
7.8.v-for 与 v-if 一同使用
不推荐在同一元素上使用 v-if 和 v-for
当它们处于同一节点,v-if 的优先级比 v-for 更高,这意味着 v-if 将没有权限访问 v-for 里的变量
<!-- This will throw an error because property "todo" is not defined on instance. -->
<liv-for="todo in todos"v-if="!todo.isComplete">
{{ todo }}
</li>
//可以把 v-for 移动到<template>标签中来修正:
<templatev-for="todo in todos">
<liv-if="!todo.isComplete">
{{ todo }}
</li>
</template>
7.9.在组件上使用v-for
八.事件处理
8.1.监听事件
使用v-on: (简写: @)来监听事件,用法为 v-on:click="methodName"
v-on可以接收需要调用的方法名称
8.2.事件处理方法
通过事件方法传入到v-on里面
8.3.内联处理器中的方法
<divid="inline-handler">
<button@click="say('hi')">Say hi</button>
<button@click="say('what')">Say what</button>
</div>
Vue.createApp({
methods: {
say(message) {
alert(message)
}
}
}).mount('#inline-handler')
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:
<button@click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
// ...
methods: {
warn(message,event) {
// now we have access to the native event
if(event) {
event.preventDefault()
}
alert(message)
}
}
8.4.多事件处理器
事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:
<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button@click="one($event), two($event)">
Submit
</button>
8.5.事件修饰符
.stop
.prevent
.capture
.self
.once
.passive
8.6.按键修饰符
按键别名
Vue 为最常用的键提供了别名:
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
8.7.系统修饰键
.ctrl
.alt
.shift
.meta
.exact 修饰符
.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button@click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button@click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button@click.exact="onClick">A</button>
鼠标按钮修饰键
.left
.right
.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
8.8.为什么在HTML中监听事件
九.表单输入绑定
9.1.基础用法
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
text 和 textarea 元素使用 value property 和 input 事件;
checkbox 和 radio 使用 checked property 和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。
文本(text)
<inputv-model="message"placeholder="edit me"/>
多行文本(textarea)
<textareav-model="message"placeholder="add text"></textarea>
<!-- bad 这样text里的值不起作用-->
<textarea>{{ text }}</textarea>
复选框(Checkbox)
<!-- v-model会自动绑定到checked属性上 -->
<inputtype="checkbox"id="checkbox"v-model="checked"/>
<labelfor="checkbox">{{ checked }}</label>
<!-- 多个复选框绑定到同一个数组 -->
<divid="v-model-multiple-checkboxes">
<inputtype="checkbox"id="jack"value="Jack"v-model="checkedNames"/>
<labelfor="jack">Jack</label>
<inputtype="checkbox"id="john"value="John"v-model="checkedNames"/>
<labelfor="john">John</label>
<br/>
<span>Checked names: {{ checkedNames }}</span>
</div>
<script>
Vue.createApp({
data() {
return{
checkedNames: []
}
}
}).mount('#v-model-multiple-checkboxes')
</script>
单选框(Radio)
<divid="v-model-radiobutton">
<inputtype="radio"id="one"value="One"v-model="picked"/>
<labelfor="one">One</label>
<br/>
<inputtype="radio"id="two"value="Two"v-model="picked"/>
<labelfor="two">Two</label>
<br/>
<span>Picked: {{ picked }}</span>
</div>
<!-- value值是用来区分是否可以只选择一个的 -->
Vue.createApp({
data() {
return{
picked:''
}
}
}).mount('#v-model-radiobutton')
选择框(Select)
v-model绑定的是value值
单选时:
<divid="v-model-select"class="demo">
<selectv-model="selected">
//推荐使用禁用选项
<optiondisabledvalue="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return{
selected:''
}
}
}).mount('#v-model-select')
多选时(绑定到一个数组):
属性后面需要加一个multiple
data的 return里面也需要一个空数组或者``
//用v-for循环遍历,:value="option.value,此时v-model绑定的是option.value里的值
<divid="v-model-select-dynamic"class="demo">
<selectv-model="selected">
<optionv-for="option in options":value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return{
selected:'A',
options: [
{text:'One',value:'A'},
{text:'Two',value:'B'},
{text:'Three',value:'C'}
]
}
}
}).mount('#v-model-select-dynamic')
9.2.值绑定
复选框
<inputtype="checkbox"v-model="toggle"true-value="yes"false-value="no"/>
// when checked:
vm.toggle==='yes'
// when unchecked:
vm.toggle==='no'
单选框
<inputtype="radio"v-model="pick"v-bind:value="a"/>
// 当选中时
vm.pick===vm.a
Select Options
<selectv-model="selected">
<!-- 内联对象字面量 -->
<option:value="{ number: 123 }">123</option>
</select>
// 当被选中时
typeofvm.selected// => 'object'
vm.selected.number// => 123
9.3.修饰符
lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组织文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:
<!-- 仅在“change”时更新 -->
<inputv-model.lazy="msg"/>
number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
<inputv-model.number="age"type="number"/>
这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。
trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
<inputv-model.trim="msg"/>
9.4.在组件上使用v-model
组件使用和其他普通标签使用方法一样
十.组件基础
10.1.基本实例
<divid="components-demo">
//可以重复多次使用
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script>
// 创建一个VUE应用
constapp=Vue.createApp({})
// 定义一个名字为button-counter的全局组件
app.component('button-counter', {
data() {
return{
count:0
}
},
template:`
<button v-on:click="count++">
You clicked me {{ count }} times.
</button>`
})
//挂载id
app.mount('#components-demo')
</script>
10.2.组件的复用
10.3.组建的组织
通常会以树的形式来组织
组件的注册类型分两种:全局组件和局部组件
10.4.通过Props向子组件传递数据
constApp={
data() {
return{
posts: [
{id:1,title:'My journey with Vue'},
{id:2,title:'Blogging with Vue'},
{id:3,title:'Why Vue is so fun'}
]
}
}
}
constapp=Vue.createApp({})
app.component('blog-post', {
props: ['title'],
template:`<h4>{{ title }}</h4>`
})
app.mount('#blog-posts-demo')
每篇博文渲染一个组件:
<divid="blog-posts-demo">
<blog-post
v-for="post in posts"
:key="post.id"
:title="post.title"
></blog-post>
</div>
10.5.监听子组件事件
使用事件抛出一个值
有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让 <blog-post> 组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值:
<button@click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>
然后当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值:
<blog-post...@enlarge-text="postFontSize += $event"></blog-post>
或者,如果这个事件处理函数是一个方法:
<blog-post...@enlarge-text="onEnlargeText"></blog-post>
那么这个值将会作为第一个参数传入这个方法:
methods: {
onEnlargeText(enlargeAmount) {
this.postFontSize+=enlargeAmount
}
}
在组件上使用 v-model
为了让它正常工作,这个组件内的 <input> 必须:
将其 value attribute 绑定到一个名叫 modelValue 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 update:modelValue 事件抛出
写成代码之后是这样的:
app.component('custom-input', {
props: ['modelValue'],
template:`
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
`
})
现在 v-model 就应该可以在这个组件上完美地工作起来了:
<custom-inputv-model="searchText"></custom-input>
使用计算属性来设置组件上使用V-model(通过重构set和get)
app.component('custom-input', {
props: ['modelValue'],
template:`
<input v-model="value">
`,
computed: {
value: {
get() {
returnthis.modelValue
},
set(value) {this.$emit('update:modelValue',value)
}
}
}
})
10.6.通过插槽分发内容
app.component('alert-box', {
template:`
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
10.7.动态组件
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component:is="currentTabComponent"></component>
10.8.解析DOM模板时的注意事项
有些标签是只能出现在某一些特定的元素当中的,
用v-is就可以比较好的处理这一个问题
<!-- 错误的,这样不会渲染任何东西 -->
<trv-is="blog-post-row"></tr>
<!-- 正确的 -->
<trv-is="'blog-post-row'"></tr>
另外,HTML 属性名不区分大小写,因此浏览器将把所有大写字符解释为小写。这意味着当你在 DOM 模板中使用时,驼峰 prop 名称和 event 处理器参数需要使用它们的 kebab-cased (横线字符分隔) 等效值:
// 在JavaScript中的驼峰
app.component('blog-post', {
props: ['postTitle'],
template:`
<h3>{{ postTitle }}</h3>
`
})
<!-- 在HTML则是横线字符分割 -->
<blog-postpost-title="hello!"></blog-post>
需要注意的是如果我们从以下来源使用模板的话,这条限制是*不存在*的:
字符串模板 (例如:template: '...')
<script type="text/x-template">