doc: update vue2.md. (#5)

This commit is contained in:
jaywcjlove 2022-10-11 14:50:42 +08:00
parent 078df00bf5
commit 518249913e

View File

@ -12,6 +12,7 @@ Vue 是一套用于构建用户界面的渐进式框架
- [Vue 2.x 官方文档](https://v2.cn.vuejs.org/)
- [Vue Router 3.x 官方文档](https://v3.router.vuejs.org/)
<!--rehype:className=style-round-->
#### 快速创建 **Vue** 项目 ([Vue CLI](https://cli.vuejs.org/zh/guide/creating-a-project.html))
@ -27,6 +28,8 @@ npx @vue/cli create hello-world
</div>
```
---
```js
var app = new Vue({
el: '#app',
@ -48,6 +51,8 @@ var app = new Vue({
</div>
```
---
```js
var vm = new Vue({
el: '#example',
@ -82,6 +87,8 @@ var vm = new Vue({
</div>
```
---
```js
var app2 = new Vue({
el: '#app-2',
@ -100,6 +107,8 @@ var app2 = new Vue({
</div>
```
---
```js
var app3 = new Vue({
el: '#app-3',
@ -123,6 +132,8 @@ var app3 = new Vue({
</div>
```
---
```js
var app4 = new Vue({
el: '#app-4',
@ -147,6 +158,8 @@ var app4 = new Vue({
</div>
```
---
```js
var app5 = new Vue({
el: '#app-5',
@ -706,8 +719,11 @@ var example2 = new Vue({
}
}
})
```
// 也可以用 JavaScript 直接调用方法
也可以用 JavaScript 直接调用方法
```js
example2.greet() // => 'Hello Vue.js!'
```
@ -784,7 +800,9 @@ methods: {
<!-- 滚动事件的默认行为(即滚动行为)会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 包含 event.preventDefault() 的情况 -->
<p v-on:scroll.passive="onScroll">...</p>
<p v-on:scroll.passive="onScroll">
...
</p>
```
这个 `.passive` [修饰符](#v-on-事件修饰符)尤其能够提升移动端的性能。
@ -802,7 +820,6 @@ methods: {
<div v-on:click.ctrl="doSomething">
```
### .exact 修饰符
```html
@ -814,6 +831,651 @@ methods: {
<button v-on:click.exact="onClick">
```
计算属性和侦听器
---
### 基础例子
```html
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>
计算的反向消息: "{{ reversedMessage }}"
</p>
</div>
```
```js
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('')
.reverse().join('')
}
}
})
```
### 计算属性缓存 vs 方法
```html
<p>
计算的反向消息:"{{ reversedMessage() }}"
</p>
```
在组件中,我们可以将同一函数定义为一个方法而不是一个计算属性
```js
methods: {
reversedMessage: function () {
return this.message.split('')
.reverse().join('')
}
}
```
两种方式的最终结果确实是完全相同的。然而,不同的是**计算属性是基于它们的响应式依赖进行缓存的**。
### 计算属性 vs 侦听属性
<!--rehype:wrap-class=row-span-2-->
```html
<div id="demo">{{ fullName }}</div>
```
```js
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName =
val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName =
this.firstName + ' ' + val
}
}
})
```
上面代码是命令式且重复的。将它与计算属性的版本进行比较:
```js
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName
+ ' ' + this.lastName
}
}
})
```
### 计算属性的 setter
<!--rehype:wrap-class=col-span-2-->
```js
computed: {
fullName: {
get: function () { // getter
return this.firstName + ' ' + this.lastName
},
set: function (newValue) { // setter
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
```
表单输入绑定
---
### 文本
```html
<input v-model="msg" placeholder="编辑我">
<p>msg is: {{ msg }}</p>
```
### 多行文本
```html {3}
<span>Multiline message is:</span>
<textarea
v-model="message"
placeholder="添加多行"></textarea>
<p>{{ message }}</p>
```
### 复选框
```html {4}
<input
type="checkbox"
id="checkbox"
v-model="checked"
>
<label for="checkbox">{{ checked}}</label>
```
### 多个复选框
<!--rehype:wrap-class=col-span-2-->
```html
<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>
```
如下 data
```js
new Vue({
el: '...',
data: {
checkedNames: []
}
})
```
### 单选按钮
```html
<div id="example-4">
<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>
<div>Picked: {{ picked }}</div>
</div>
```
---
```js
new Vue({
el: '#example-4',
data: {
picked: ''
}
})
```
### 选择框
```html
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
```
---
```js
new Vue({
el: '...',
data: {
selected: ''
}
})
```
### 选择框(数组)
```html
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<div>Selected: {{ selected }}</div>
```
---
```js
new Vue({
el: '...',
data: {
selected: []
}
})
```
### v-for 渲染的动态选项
<!--rehype:wrap-class=row-span-2-->
```html {3-4}
<select v-model="selected">
<option
v-for="option in options"
v-bind:value="option.value"
>
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
```
---
```js {6-8}
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
```
### 值绑定
```html
<!-- 当选中时pc 为字符串 "a" -->
<input type="radio" v-model="pc" value="a">
<!-- toggle 为 true 或 false -->
<input type="checkbox" v-model="toggle">
<!-- 选中第一个选项时selected为字符串 abc -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
```
### 单选按钮
```html
<input
type="radio"
v-model="pick"
v-bind:value="a">
```
当选中时
```js
vm.pick === vm.a
```
### 复选框
```html {3}
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
```
---
```js
// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'
```
### 选择框的选项
```html
<select v-model="selected">
<!-- 内联对象字面量 -->
<option v-bind:value="{ number: 123 }">
123
</option>
</select>
```
当选中时
```js
typeof vm.selected // => 'object'
vm.selected.number // => 123
```
### 修饰符
```html
<!-- lazy:在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
<!-- number:自动将用户的输入值转为数值类型 -->
<input v-model.number="age" type="number">
<!-- trim:自动过滤用户输入的首尾空白字符 -->
<input v-model.trim="msg">
```
组件基础
---
### 基本示例
<!--rehype:wrap-class=row-span-2-->
```js
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: `
<button v-on:click="count++">
你点击了我 {{ count }} 次
</button>
`
})
```
组件是可复用的 `Vue` 实例
```html
<div id="components-demo">
<button-counter></button-counter>
</div>
```
---
```js
new Vue({
el: '#components-demo'
})
```
组件的复用
```html
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
```
### `data` 必须是一个函数
```js
data: function () {
return {
count: 0
}
}
```
组件的 `data` 选项必须是一个函数
### 向子组件传递数据
```js
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
```
当值传递给一个 `prop` `attribute` 的时候,变成了组件实例的一个 `property`
```html
<blog-post title="写博客"></blog-post>
<blog-post title="如此有趣"></blog-post>
```
### 单个根元素
```js {4}
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
```
---
```html
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
>
</blog-post>
```
### 监听子组件事件
<!--rehype:wrap-class=row-span-2-->
```js {7}
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button
v-on:click="$emit('enlarge-txt')"
>
Enlarge text
</button>
<div v-html="post.content"></div>
</div>
`
})
```
---
```html {3}
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
```
可以使用 `$emit` 的第二个参数来提供这个值
```html {2}
<button
v-on:click="$emit('enlarge-text', 0.1)"
>
Enlarge text
</button>
```
通过 `$event` 访问到被抛出的这个值
```html {3}
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
```
如果这个事件处理函数是一个方法
```html {3}
<blog-post
...
v-on:enlarge-text="onEnlargeText"
></blog-post>
```
那么这个值将会作为第一个参数传入这个方法
```js
methods: {
onEnlargeText: function(enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
```
### 在组件上使用 v-model
<!--rehype:wrap-class=col-span-2-->
```html
<input v-model="searchText">
```
等价于
```html
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value">
```
为了让它正常工作,这个组件内的 \<input> 必须:
- 将其 `value` attribute 绑定到一个名叫 `value``prop`
- 在其 `input` 事件被触发时,将新的值通过自定义的 `input` 事件抛出
---
```js
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
```
现在 `v-model` 就应该可以在这个组件上完美地工作起来了
```html {2}
<custom-input
v-model="searchText"
>
</custom-input>
```
### 通过插槽分发内容
```html
<alert-box>
发生了不好的事情。
</alert-box>
```
---
```js {5}
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
```
### 动态组件示例
<!--rehype:wrap-class=col-span-2 row-span-2-->
```html
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab"
v-bind:class="['tab-button', { active: currentTab === tab }]"
v-on:click="currentTab = tab"
>
{{ tab }}
</button>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div>
<script>
Vue.component("tab-home", {
template: "<div>Home component</div>"
});
Vue.component("tab-posts", {
template: "<div>Posts component</div>"
});
Vue.component("tab-archive", {
template: "<div>Archive component</div>"
});
new Vue({
el: "#dynamic-component-demo",
data: {
currentTab: "Home",
tabs: ["Home", "Posts", "Archive"]
},
computed: {
currentTabComponent: function() {
return "tab-" + this.currentTab.toLowerCase();
}
}
});
</script>
```
### 解析 DOM 模板时的注意事项
有些 HTML 元素,诸如 `<ul>``<ol>``<table>``<select>`,对于哪些元素可以出现在其内部是有严格限制的。有些元素,诸如 `<li>``<tr>``<option>`,只能出现在其它某些特定的元素内部
```html
<table>
<blog-post-row></blog-post-row>
</table>
```
`<blog-post-row>` 会被作为无效的内容提升到外部
---
如果我们从以下来源使用模板的话,这条限制是不存在的
- 字符串 (例如template: '...')
- 单文件组件 (.vue)
- `<script type="text/x-template">`
<!--rehype:className=style-round-->
Vue 2 API 参考
---