From fea44dc1e57f01b6d395d0f8e99f785a0b83655e Mon Sep 17 00:00:00 2001 From: jaywcjlove Date: Tue, 11 Oct 2022 06:51:33 +0000 Subject: [PATCH] doc: update `vue2.md`. (#5) 518249913ec6d434193001f2afc3df7fefd7a1cc --- docs/vue2.html | 499 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 494 insertions(+), 5 deletions(-) diff --git a/docs/vue2.html b/docs/vue2.html index 8e6eb141..3d05b290 100644 --- a/docs/vue2.html +++ b/docs/vue2.html @@ -39,10 +39,11 @@

入门

介绍

Vue 是一套用于构建用户界面的渐进式框架

-

快速创建 Vue 项目 (Vue CLI)

npx @vue/cli create hello-world
 
@@ -51,6 +52,7 @@ {{ message }} </div> +
var app = new Vue({
   el: '#app',
   data: {
@@ -67,6 +69,7 @@
   </p>
 </div>
 
+
var vm = new Vue({
   el: '#example',
   data: {
@@ -93,6 +96,7 @@
   </span>
 </div>
 
+
var app2 = new Vue({
   el: '#app-2',
   data: {
@@ -106,6 +110,7 @@
   <p v-if="seen">现在你看到我了</p>
 </div>
 
+
var app3 = new Vue({
   el: '#app-3',
   data: {
@@ -123,6 +128,7 @@
   </ol>
 </div>
 
+
var app4 = new Vue({
   el: '#app-4',
   data: {
@@ -142,6 +148,7 @@
   </button>
 </div>
 
+
var app5 = new Vue({
   el: '#app-5',
   data: {
@@ -517,9 +524,9 @@
     }
   }
 })
-
-// 也可以用 JavaScript 直接调用方法
-example2.greet() // => 'Hello Vue.js!'
+
+

也可以用 JavaScript 直接调用方法

+
example2.greet() // => 'Hello Vue.js!'
 

内联处理器中的方法

@@ -579,7 +586,9 @@
<!-- 滚动事件的默认行为(即滚动行为)会立即触发 -->
 <!-- 而不会等待 `onScroll` 完成  -->
 <!-- 包含 event.preventDefault() 的情况 -->
-<p v-on:scroll.passive="onScroll">...</p>
+<p v-on:scroll.passive="onScroll">
+  ...
+</p>
 

这个 .passive 修饰符尤其能够提升移动端的性能。

按键修饰符

@@ -600,6 +609,486 @@ <!-- 没有任何系统修饰符被按下的时候才触发 --> <button v-on:click.exact="onClick"> +

计算属性和侦听器

+

基础例子

+
<div id="example">
+  <p>Original message: "{{ message }}"</p>
+  <p>
+    计算的反向消息: "{{ reversedMessage }}"
+  </p>
+</div>
+
+
var vm = new Vue({
+  el: '#example',
+  data: {
+    message: 'Hello'
+  },
+  computed: {
+    // 计算属性的 getter
+    reversedMessage: function () {
+      // `this` 指向 vm 实例
+      return this.message.split('')
+                  .reverse().join('')
+    }
+  }
+})
+
+

计算属性缓存 vs 方法

+
<p>
+  计算的反向消息:"{{ reversedMessage() }}"
+</p>
+
+

在组件中,我们可以将同一函数定义为一个方法而不是一个计算属性

+
methods: {
+  reversedMessage: function () {
+    return this.message.split('')
+                .reverse().join('')
+  }
+}
+
+

两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的

+

计算属性 vs 侦听属性

+ +
<div id="demo">{{ fullName }}</div>
+
+
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
+    }
+  }
+})
+
+

上面代码是命令式且重复的。将它与计算属性的版本进行比较:

+
var vm = new Vue({
+  el: '#demo',
+  data: {
+    firstName: 'Foo',
+    lastName: 'Bar'
+  },
+  computed: {
+    fullName: function () {
+      return this.firstName 
+        + ' ' + this.lastName
+    }
+  }
+})
+
+

计算属性的 setter

+ +
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]
+    }
+  }
+}
+
+

表单输入绑定

+

文本

+
<input v-model="msg" placeholder="编辑我">
+<p>msg is: {{ msg }}</p>
+
+

多行文本

+
<span>Multiline message is:</span>
+<textarea
+  v-model="message"
+  placeholder="添加多行"></textarea>
+<p>{{ message }}</p>
+
+

复选框

+
<input
+  type="checkbox"
+  id="checkbox"
+  v-model="checked"
+>
+<label for="checkbox">{{ checked}}</label>
+
+

多个复选框

+ +
<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

+
new Vue({
+  el: '...',
+  data: {
+    checkedNames: []
+  }
+})
+
+

单选按钮

+
<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>
+
+
+
new Vue({
+  el: '#example-4',
+  data: {
+    picked: ''
+  }
+})
+
+

选择框

+
<select v-model="selected">
+  <option disabled value="">请选择</option>
+  <option>A</option>
+  <option>B</option>
+  <option>C</option>
+</select>
+<span>Selected: {{ selected }}</span>
+
+
+
new Vue({
+  el: '...',
+  data: {
+    selected: ''
+  }
+})
+
+

选择框(数组)

+
<select v-model="selected" multiple>
+  <option>A</option>
+  <option>B</option>
+  <option>C</option>
+</select>
+<div>Selected: {{ selected }}</div>
+
+
+
new Vue({
+  el: '...',
+  data: {
+    selected: []
+  }
+})
+
+

v-for 渲染的动态选项

+ +
<select v-model="selected">
+  <option
+    v-for="option in options"
+    v-bind:value="option.value"
+  >
+    {{ option.text }}
+  </option>
+</select>
+<span>Selected: {{ selected }}</span>
+
+
+
new Vue({
+  el: '...',
+  data: {
+    selected: 'A',
+    options: [
+      { text: 'One', value: 'A' },
+      { text: 'Two', value: 'B' },
+      { text: 'Three', value: 'C' }
+    ]
+  }
+})
+
+

值绑定

+
<!-- 当选中时,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>
+
+

单选按钮

+
<input
+  type="radio"
+  v-model="pick"
+  v-bind:value="a">
+
+

当选中时

+
vm.pick === vm.a
+
+

复选框

+
<input
+  type="checkbox"
+  v-model="toggle"
+  true-value="yes"
+  false-value="no"
+>
+
+
+
// 当选中时
+vm.toggle === 'yes'
+// 当没有选中时
+vm.toggle === 'no'
+
+

选择框的选项

+
<select v-model="selected">
+  <!-- 内联对象字面量 -->
+  <option v-bind:value="{ number: 123 }">
+    123
+  </option>
+</select>
+
+

当选中时

+
typeof vm.selected // => 'object'
+vm.selected.number // => 123
+
+

修饰符

+
<!-- lazy:在“change”时而非“input”时更新 -->
+<input v-model.lazy="msg">
+
+<!-- number:自动将用户的输入值转为数值类型 -->
+<input v-model.number="age" type="number">
+
+<!-- trim:自动过滤用户输入的首尾空白字符 -->
+<input v-model.trim="msg">
+
+

组件基础

+

基本示例

+ +
Vue.component('button-counter', {
+  data: function () {
+    return {
+      count: 0
+    }
+  },
+  template: `
+    <button v-on:click="count++">
+      你点击了我 {{ count }} 次
+    </button>
+  `
+})
+
+

组件是可复用的 Vue 实例

+
<div id="components-demo">
+  <button-counter></button-counter>
+</div>
+
+
+
new Vue({
+  el: '#components-demo'
+})
+
+

组件的复用

+
<div id="components-demo">
+  <button-counter></button-counter>
+  <button-counter></button-counter>
+  <button-counter></button-counter>
+</div>
+
+

data 必须是一个函数

+
data: function () {
+  return {
+    count: 0
+  }
+}
+
+

组件的 data 选项必须是一个函数

+

向子组件传递数据

+
Vue.component('blog-post', {
+  props: ['title'],
+  template: '<h3>{{ title }}</h3>'
+})
+
+

当值传递给一个 prop attribute 的时候,变成了组件实例的一个 property

+
<blog-post title="写博客"></blog-post>
+<blog-post title="如此有趣"></blog-post>
+
+

单个根元素

+
Vue.component('blog-post', {
+  props: ['post'],
+  template: `
+    <div class="blog-post">
+      <h3>{{ post.title }}</h3>
+      <div v-html="post.content"></div>
+    </div>
+  `
+})
+
+
+
<blog-post
+  v-for="post in posts"
+  v-bind:key="post.id"
+  v-bind:post="post"
+>
+</blog-post>
+
+

监听子组件事件

+ +
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>
+  `
+})
+
+
+
<blog-post
+  ...
+  v-on:enlarge-text="postFontSize += 0.1"
+></blog-post>
+
+

可以使用 $emit 的第二个参数来提供这个值

+
<button
+  v-on:click="$emit('enlarge-text', 0.1)"
+>
+  Enlarge text
+</button>
+
+

通过 $event 访问到被抛出的这个值

+
<blog-post
+  ...
+  v-on:enlarge-text="postFontSize += $event"
+></blog-post>
+
+

如果这个事件处理函数是一个方法

+
<blog-post
+  ...
+  v-on:enlarge-text="onEnlargeText"
+></blog-post>
+
+

那么这个值将会作为第一个参数传入这个方法

+
methods: {
+  onEnlargeText: function(enlargeAmount) {
+    this.postFontSize += enlargeAmount
+  }
+}
+
+

在组件上使用 v-model

+ +
<input v-model="searchText">
+
+

等价于

+
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value">
+
+

为了让它正常工作,这个组件内的 <input> 必须:

+
    +
  • 将其 value attribute 绑定到一个名叫 valueprop
  • +
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
  • +
+
+
Vue.component('custom-input', {
+  props: ['value'],
+  template: `
+    <input
+      v-bind:value="value"
+      v-on:input="$emit('input', $event.target.value)"
+    >
+  `
+})
+
+

现在 v-model 就应该可以在这个组件上完美地工作起来了

+
<custom-input
+  v-model="searchText"
+>
+</custom-input>
+
+

通过插槽分发内容

+
<alert-box>
+  发生了不好的事情。
+</alert-box>
+
+
+
Vue.component('alert-box', {
+  template: `
+    <div class="demo-alert-box">
+      <strong>Error!</strong>
+      <slot></slot>
+    </div>
+  `
+})
+
+

动态组件示例

+ +
<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>,只能出现在其它某些特定的元素内部

+
<table>
+  <blog-post-row></blog-post-row>
+</table>
+
+

<blog-post-row> 会被作为无效的内容提升到外部

+
+

如果我们从以下来源使用模板的话,这条限制是不存在的

+
    +
  • 字符串 (例如:template: '...')
  • +
  • 单文件组件 (.vue)
  • +
  • <script type="text/x-template">
  • +
+

Vue 2 API 参考

全局配置