精华内容
下载资源
问答
  • VUE 中文文档

    2020-09-15 20:41:54
    VUE 中文文档本地化 近期家里网络不太好,看 VUE 文档有时都没有办法看。所以研究了一下 将 VUE文档加载到本地,享受没网的时候也能畅游学习。同时将这个方法 分享给大家。

    近期家里网络不太好,看 VUE 文档有时都没有办法看。所以研究了一下 将 VUE文档加载到本地,享受没网的时候也能畅游学习。同时将这个方法 分享给大家。

    1. 下载源码

    • 首先 要先进入 GitHub 网站 将 VUE 的 中文 Doc文档 下载下来。

    • 地址:https://github.com/vuejs/docs-next-zh-cn

    • image-20200914225508449
    • 然后解压 文件夹,并放到合适的目录下 PS (我这里放到了 E:\Project\docs-next-zh-cn-master 目录下)

    • 因为 VUE 的中文 文档是基于 Vuepress 构建而成的,内容是在 src 文件内,格式为 Markdown。

    • 所以 我们 要下载 node.js 进行支持,并下载一些依赖文件。

    2. node.js 的下载与配置

    • node.js 官网:https://nodejs.org/en/

    • image-20200914231320113

    • 我是复制下载链接,通过迅雷下载的。唉,官网不友好啊,下载速度慢。

    • 下载 完成以后,双击进行安装,一路 next 搞定。

    • # 安装完成 以后  按 windows键 + R 输入 cmd  进入 dos 窗口输入  
      node -v   #进行 查看 版本,显示版本 则成功安装。
      
    • 因为node.js 是国外的,跟maven一样 要配置国内的镜像

    • # dos 窗口 输入 
      
      // 设置 淘宝镜像源
      npm config set registry https://registry.npm.taobao.org
      
      // 查看 使用的 镜像源
      npm config get registry
      
      // 安装 淘宝镜像源
      npm install -g cnpm --registry=https://registry.npm.taobao.org
      // 安装 
      npm install -g vuepress
      

    3. 部署项目

    • 使用 dos 窗口 进入 VUE 文档的解压目录

    • # 例如 我的
      E:	#进入E 盘
      cd  Project/docs-next-zh-cn-master 	# 进入目录中
      npm install 	# 加载依赖 
      npm run serve		# 当依赖加载完毕之后,启动项目(之后启动也是这么启动)
      

      image-20200915203727100

    dos 窗口 关闭会导致本地页面不能访问哦,因为 它是前台 服务,一旦你关闭,它就会认为 你不使用了,然后将服务kill 掉咯

    4. 一键启动服务

    如果使用 dos命令的话,还要进入窗口进行操作,作为一个懒人,咱们肯定嫌弃麻烦咯

    首先创建一个文本
    然后将 代码粘贴到 文本中保存
    
    cmd /k "cd /d E:\Project\docs-next-zh-cn-master&&npm run serve"
    
    保存 文件,并将文件后缀 改为 .bat 格式
    然后 每一次 启动,直接双击运行。
    

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • Vue.js是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既...

    Vue.js是什么
    Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

    起步
    安装和引入Vue

    声明式渲染
    Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:

    <div id="app">
      {{ message }}
    </div>
    
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!'
      }
    })
    

    除了文本插值,我们还可以像这样来绑定元素特性:

    <div id="app-2">
      <span v-bind:title="message">
        鼠标悬停几秒钟查看此处动态绑定的提示信息!
      </span>
    </div>
    var app2 = new Vue({
      el: '#app-2',
      data: {
        message: '页面加载于 ' + new Date().toLocaleString()
      }
    })
    

    这里我们遇到了一点新东西。你看到的 v-bind 特性被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊特性。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 title 特性和 Vue 实例的 message 属性保持一致”。

    条件与循环
    控制切换一个元素是否显示也相当简单:

    <div id="app-3">
      <p v-if="seen">现在你看到我了</p>
    </div>
    var app3 = new Vue({
      el: '#app-3',
      data: {
        seen: true
      }
    })
    

    这个例子演示了我们不仅可以把数据绑定到 DOM 文本或特性,还可以绑定到 DOM 结构。此外,Vue 也提供一个强大的过渡效果系统,可以在 Vue 插入/更新/移除元素时自动应用过渡效果。
    还有其它很多指令,每个都有特殊的功能。例如,v-for 指令可以绑定数组的数据来渲染一个项目列表:

    <div id="app-4">
      <ol>
        <li v-for="todo in todos">
          {{ todo.text }}
        </li>
      </ol>
    </div>
    var app4 = new Vue({
      el: '#app-4',
      data: {
        todos: [
          { text: '学习 JavaScript' },
          { text: '学习 Vue' },
          { text: '整个牛项目' }
        ]
      }
    })
    

    处理用户输入
    为了让用户和你的应用进行交互,我们可以用 v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法:

    <div id="app-5">
      <p>{{ message }}</p>
      <button v-on:click="reverseMessage">逆转消息</button>
    </div>
    var app5 = new Vue({
      el: '#app-5',
      data: {
        message: 'Hello Vue.js!'
      },
      methods: {
        reverseMessage: function () {
          this.message = this.message.split('').reverse().join('')
        }
      }
    })
    

    Vue 还提供了 v-model 指令,它能轻松实现表单输入和应用状态之间的双向绑定。

    <div id="app-6">
      <p>{{ message }}</p>
      <input v-model="message">
    </div>
    var app6 = new Vue({
      el: '#app-6',
      data: {
        message: 'Hello Vue!'
      }
    })
    

    组件化应用构建
    组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
    在这里插入图片描述
    在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单:

    Vue.component('todo-item', {
      template: '<li>这是个待办项</li>'
    })
    

    现在你可以用它构建另一个组件模板:

    <ol>
      <!-- 创建一个 todo-item 组件的实例 -->
      <todo-item></todo-item>
    </ol>
    

    但是这样会为每个待办项渲染同样的文本,这看起来并不炫酷。我们应该能从父作用域将数据传到子组件才对。让我们来修改一下组件的定义,使之能够接受一个 prop:

    Vue.component('todo-item', {
      // todo-item 组件现在接受一个
      // "prop",类似于一个自定义特性。
      // 这个 prop 名为 todo。
      props: ['todo'],
      template: '<li>{{ todo.text }}</li>'
    })
    

    现在,我们可以使用 v-bind 指令将待办项传到循环输出的每个组件中:

    <div id="app-7">
      <ol>
        <!--
          现在我们为每个 todo-item 提供 todo 对象
          todo 对象是变量,即其内容可以是动态的。
          我们也需要为每个组件提供一个“key”,稍后再
          作详细解释。
        -->
        <todo-item
          v-for="item in groceryList"
          v-bind:todo="item"
          v-bind:key="item.id">
        </todo-item>
      </ol>
    </div>
    Vue.component('todo-item', {
      props: ['todo'],
      template: '<li>{{ todo.text }}</li>'
    })
    
    var app7 = new Vue({
      el: '#app-7',
      data: {
        groceryList: [
          { id: 0, text: '蔬菜' },
          { id: 1, text: '奶酪' },
          { id: 2, text: '随便其它什么人吃的东西' }
        ]
      }
    })
    

    尽管这只是一个刻意设计的例子,但是我们已经设法将应用分割成了两个更小的单元。子单元通过 prop 接口与父单元进行了良好的解耦。我们现在可以进一步改进 组件,提供更为复杂的模板和逻辑,而不会影响到父单元。

    准备好了么





    **创建Vue实例** 每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的:
    var vm = new Vue({
      // 选项
    })
    

    虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。

    当创建一个 Vue 实例时,你可以传入一个选项对象。这篇教程主要描述的就是如何使用这些选项来创建你想要的行为。作为参考,你也可以在 API 文档 中浏览完整的选项列表。

    一个 Vue 应用由一个通过 new Vue 创建的根 Vue 实例,以及可选的嵌套的、可复用的组件树组成。举个例子,一个 todo 应用的组件树可以是这样的:

    根实例
    └─ TodoList
       ├─ TodoItem
       │  ├─ DeleteTodoButton
       │  └─ EditTodoButton
       └─ TodoListFooter
          ├─ ClearTodosButton
          └─ TodoListStatistics
    

    数据与方法
    当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。

    // 我们的数据对象
    var data = { a: 1 }
    
    // 该对象被加入到一个 Vue 实例中
    var vm = new Vue({
      data: data
    })
    
    // 获得这个实例上的属性
    // 返回源数据中对应的字段
    vm.a == data.a // => true
    
    // 设置属性也会影响到原始数据
    vm.a = 2
    data.a // => 2
    
    // ……反之亦然
    data.a = 3
    vm.a // => 3
    

    当这些数据改变时,视图会进行重渲染。值得注意的是只有当实例被创建时 data 中存在的属性才是响应式的。也就是说如果你添加一个新的属性,比如:

    vm.b = 'hi'
    

    那么对 b 的改动将不会触发任何视图的更新。如果你知道你会在晚些时候需要一个属性,但是一开始它为空或不存在,那么你仅需要设置一些初始值。比如:

    data: {
      newTodoText: '',
      visitCount: 0,
      hideCompletedTodos: false,
      todos: [],
      error: null
    }
    

    这里唯一的例外是使用 Object.freeze(),这会阻止修改现有的属性,也意味着响应系统无法再追踪变化。

    var obj = {
      foo: 'bar'
    }
    
    Object.freeze(obj)
    
    new Vue({
      el: '#app',
      data: obj
    })
    <div id="app">
      <p>{{ foo }}</p>
      <!-- 这里的 `foo` 不会更新! -->
      <button v-on:click="foo = 'baz'">Change it</button>
    </div>
    

    实例生命周期钩子
    每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

    插值
    文本
    数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:

    <span>Message: {{ msg }}</span>
    

    Mustache 标签将会被替代为对应数据对象上 msg 属性的值。无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。

    通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:

    <span v-once>这个将不会改变: {{ msg }}</span>
    

    原始HTML
    双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:

    <p>Using mustaches: {{ rawHtml }}</p>
    <p>Using v-html directive: <span v-html="rawHtml"></span></p>
    

    在这里插入图片描述
    这个 span 的内容将会被替换成为属性值 rawHtml,直接作为 HTML——会忽略解析属性值中的数据绑定。注意,你不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎。反之,对于用户界面 (UI),组件更适合作为可重用和可组合的基本单位。
    使用javascript表达式
    迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。

    {{ number + 1 }}
    
    {{ ok ? 'YES' : 'NO' }}
    
    {{ message.split('').reverse().join('') }}
    
    <div v-bind:id="'list-' + id"></div>
    

    这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。

    <!-- 这是语句,不是表达式 -->
    {{ var a = 1 }}
    
    <!-- 流控制也不会生效,请使用三元表达式 -->
    {{ if (ok) { return message } }}
    

    指令
    指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。回顾我们在介绍中看到的例子:
    一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML 特性:

    <a v-bind:href="url">...</a>
    

    在这里 href 是参数,告知 v-bind 指令将该元素的 href 特性与表达式 url 的值绑定。

    另一个例子是 v-on 指令,它用于监听 DOM 事件:

    <a v-on:click="doSomething">...</a>
    

    缩写
    v- 前缀作为一种视觉提示,用来识别模板中 Vue 特定的特性。当你在使用 Vue.js 为现有标签添加动态行为 (dynamic behavior) 时,v- 前缀很有帮助,然而,对于一些频繁用到的指令来说,就会感到使用繁琐。同时,在构建由 Vue.js 管理所有模板的单页面应用程序 (SPA - single page application) 时,v- 前缀也变得没那么重要了。因此,Vue.js 为 v-bind 和 v-on 这两个最常用的指令,提供了特定简写:
    v-bind缩写

    <!-- 完整语法 -->
    <a v-bind:href="url">...</a>
    
    <!-- 缩写 -->
    <a :href="url">...</a>
    

    v-on缩写

    <!-- 完整语法 -->
    <a v-on:click="doSomething">...</a>
    
    <!-- 缩写 -->
    <a @click="doSomething">...</a>
    

    它们看起来可能与普通的 HTML 略有不同,但 : 与 @ 对于特性名来说都是合法字符,在所有支持 Vue.js 的浏览器都能被正确地解析。而且,它们不会出现在最终渲染的标记中。缩写语法是完全可选的,但随着你更深入地了解它们的作用,你会庆幸拥有它们。

    计算属性
    模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:

    <div id="example">
      {{ message.split('').reverse().join('') }}
    </div>
    

    在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。所以,对于任何复杂逻辑,你都应当使用计算属性。
    基础例子

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

    计算属性缓存或者方法
    你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:

    <p>Reversed message: "{{ reversedMessage() }}"</p>
    // 在组件中
    methods: {
      reversedMessage: function () {
        return this.message.split('').reverse().join('')
      }
    }
    

    我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

    这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

    computed: {
      now: function () {
        return Date.now()
      }
    }
    

    相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

    我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
    计算属性和侦听属性
    Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:

    <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
        }
      }
    })
    

    计算属性的setter
    计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

    computed: {
      fullName: {
        // getter
        get: function () {
          return this.firstName + ' ' + this.lastName
        },
        // setter
        set: function (newValue) {
          var names = newValue.split(' ')
          this.firstName = names[0]
          this.lastName = names[names.length - 1]
        }
      }
    }
    

    侦听器
    虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

    <div id="watch-example">
      <p>
        Ask a yes/no question:
        <input v-model="question">
      </p>
      <p>{{ answer }}</p>
    </div>
    
    <!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
    <!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
    <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
    <script>
    var watchExampleVM = new Vue({
      el: '#watch-example',
      data: {
        question: '',
        answer: 'I cannot give you an answer until you ask a question!'
      },
      watch: {
        // 如果 `question` 发生改变,这个函数就会运行
        question: function (newQuestion, oldQuestion) {
          this.answer = 'Waiting for you to stop typing...'
          this.debouncedGetAnswer()
        }
      },
      created: function () {
        // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
        // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
        // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
        // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
        // 请参考:https://lodash.com/docs#debounce
        this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
      },
      methods: {
        getAnswer: function () {
          if (this.question.indexOf('?') === -1) {
            this.answer = 'Questions usually contain a question mark. ;-)'
            return
          }
          this.answer = 'Thinking...'
          var vm = this
          axios.get('https://yesno.wtf/api')
            .then(function (response) {
              vm.answer = _.capitalize(response.data.answer)
            })
            .catch(function (error) {
              vm.answer = 'Error! Could not reach the API. ' + error
            })
        }
      }
    })
    </script>
    

    Class 与 Style 绑定
    操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
    绑定html的样式
    我们可以传给 v-bind:class 一个对象,以动态地切换 class:

    <div v-bind:class="{ active: isActive }"></div>
    

    上面的语法表示 active 这个 class 存在与否将取决于数据属性 isActive 的 truthiness。

    你可以在对象中传入更多属性来动态切换多个 class。此外,v-bind:class 指令也可以与普通的 class 属性共存。当有如下模板:

    <div class="static"
         v-bind:class="{ active: isActive, 'text-danger': hasError }">
    </div>
    

    和如下 data:

    data: {
      isActive: true,
      hasError: false
    }
    

    结果渲染为:

    <div class="static active"></div>
    

    当 isActive 或者 hasError 变化时,class 列表将相应地更新。例如,如果 hasError 的值为 true,class 列表将变为 “static active text-danger”
    绑定的数据对象不必内联定义在模板里:

    <div v-bind:class="classObject"></div>
    data: {
      classObject: {
        active: true,
        'text-danger': false
      }
    }
    

    渲染的结果和上面一样。我们也可以在这里绑定一个返回对象的计算属性。这是一个常用且强大的模式:

    <div v-bind:class="classObject"></div>
    data: {
      isActive: true,
      error: null
    },
    computed: {
      classObject: function () {
        return {
          active: this.isActive && !this.error,
          'text-danger': this.error && this.error.type === 'fatal'
        }
      }
    }
    

    对象语法
    v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名:

    <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
    
    
    data: {
      activeColor: 'red',
      fontSize: 30
    }
    

    直接绑定到一个样式对象通常更好,这会让模板更清晰:

    <div v-bind:style="styleObject"></div>
    data: {
      styleObject: {
        color: 'red',
        fontSize: '13px'
      }
    }
    

    条件渲染 v-if
    在字符串模板中,比如 Handlebars,我们得像这样写一个条件块:

    {{#if ok}}
      <h1>Yes</h1>
    {{/if}}
    

    在 Vue 中,我们使用 v-if 指令实现同样的功能:

    <h1 v-if="ok">Yes</h1>
    

    也可以用 v-else 添加一个“else 块”:

    <h1 v-if="ok">Yes</h1>
    <h1 v-else>No</h1>
    

    在 元素上使用 v-if 条件渲染分组
    因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 元素。

    <template v-if="ok">
      <h1>Title</h1>
      <p>Paragraph 1</p>
      <p>Paragraph 2</p>
    </template>
    

    你可以使用 v-else 指令来表示 v-if 的“else 块”:

    <div v-if="Math.random() > 0.5">
      Now you see me
    </div>
    <div v-else>
      Now you don't
    </div>
    

    v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
    v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:

    <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
    

    类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后
    用 key 管理可复用的元素
    Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

    <template v-if="loginType === 'username'">
      <label>Username</label>
      <input placeholder="Enter your username">
    </template>
    <template v-else>
      <label>Email</label>
      <input placeholder="Enter your email address">
    </template>
    

    那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素, 不会被替换掉——仅仅是替换了它的 placeholder。

    自己动手试一试,在输入框中输入一些文本,然后按下切换按钮:
    在这里插入图片描述
    这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key 属性即可:

    <template v-if="loginType === 'username'">
      <label>Username</label>
      <input placeholder="Enter your username" key="username-input">
    </template>
    <template v-else>
      <label>Email</label>
      <input placeholder="Enter your email address" key="email-input">
    </template>
    

    v-show
    另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样:

    <h1 v-show="ok">Hello!</h1>
    

    不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
    注意,v-show 不支持 元素,也不支持 v-else。
    v-if vs v-show
    v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

    v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

    相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

    一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

    列表渲染
    用 v-for 把一个数组对应为一组元素
    我们用 v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名。

    <ul id="example-1">
      <li v-for="item in items">
        {{ item.message }}
      </li>
    </ul>
    var example1 = new Vue({
      el: '#example-1',
      data: {
        items: [
          { message: 'Foo' },
          { message: 'Bar' }
        ]
      }
    })
    

    在 v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引。

    <ul id="example-2">
      <li v-for="(item, index) in items">
        {{ parentMessage }} - {{ index }} - {{ item.message }}
      </li>
    </ul>
    var example2 = new Vue({
      el: '#example-2',
      data: {
        parentMessage: 'Parent',
        items: [
          { message: 'Foo' },
          { message: 'Bar' }
        ]
      }
    })
    

    你也可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法:

    <div v-for="item of items"></div>
    

    一个对象的 v-for
    你也可以用 v-for 通过一个对象的属性来迭代。

    <ul id="v-for-object" class="demo">
      <li v-for="value in object">
        {{ value }}
      </li>
    </ul>
    new Vue({
      el: '#v-for-object',
      data: {
        object: {
          firstName: 'John',
          lastName: 'Doe',
          age: 30
        }
      }
    })
    

    你也可以提供第二个的参数为键名:

    <div v-for="(value, key) in object">
      {{ key }}: {{ value }}
    </div>
    

    第三个参数为索引:

    <div v-for="(value, key, index) in object">
      {{ index }}. {{ key }}: {{ value }}
    </div>
    

    key
    当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index" 。

    这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。

    为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的唯一 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值 (在这里使用简写):

    <div v-for="item in items" :key="item.id">
      <!-- 内容 -->
    </div>
    

    建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

    因为它是 Vue 识别节点的一个通用机制,key 并不与 v-for 特别关联,key 还具有其他用途,我们将在后面的指南中看到其他用途。
    变异方法
    Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:

    push()
    pop()
    shift()
    unshift()
    splice()
    sort()
    reverse()
    你打开控制台,然后用前面例子的 items 数组调用变异方法:example1.items.push({ message: ‘Baz’ }) 。
    替换数组
    变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如:filter(), concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:

    注意事项
    由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

    当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
    当你修改数组的长度时,例如:vm.items.length = newLength
    举个例子:

    var vm = new Vue({
      data: {
        items: ['a', 'b', 'c']
      }
    })
    vm.items[1] = 'x' // 不是响应性的
    vm.items.length = 2 // 不是响应性的
    

    对象更改检测注意事项
    还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:

    var vm = new Vue({
      data: {
        a: 1
      }
    })
    // `vm.a` 现在是响应式的
    
    vm.b = 2
    // `vm.b` 不是响应式的
    

    对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。例如,对于:

    var vm = new Vue({
      data: {
        userProfile: {
          name: 'Anika'
        }
      }
    })
    

    事件处理
    可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

    <div id="example-1">
      <button v-on:click="counter += 1">Add 1</button>
      <p>The button above has been clicked {{ counter }} times.</p>
    </div>
    var example1 = new Vue({
      el: '#example-1',
      data: {
        counter: 0
      }
    })
    

    事件处理方法
    然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。

    示例:

    <div id="example-2">
      <!-- `greet` 是在下面定义的方法名 -->
      <button v-on:click="greet">Greet</button>
    </div>
    var example2 = new Vue({
      el: '#example-2',
      data: {
        name: 'Vue.js'
      },
      // 在 `methods` 对象中定义方法
      methods: {
        greet: function (event) {
          // `this` 在方法里指向当前 Vue 实例
          alert('Hello ' + this.name + '!')
          // `event` 是原生 DOM 事件
          if (event) {
            alert(event.target.tagName)
          }
        }
      }
    })
    
    // 也可以用 JavaScript 直接调用方法
    example2.greet() // => 'Hello Vue.js!'
    

    事件修饰符
    在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

    为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
    .stop
    .prevent
    .capture
    .self
    .once
    .passive

    <!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">...</div>
    

    表单输入绑定
    你可以用 v-model 指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
    v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
    对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。

    组件基础
    这里有一个 Vue 组件的示例:

    // 定义一个名为 button-counter 的新组件
    Vue.component('button-counter', {
      data: function () {
        return {
          count: 0
        }
      },
      template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    })
    

    组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

    <div id="components-demo">
      <button-counter></button-counter>
    </div>
    new Vue({ el: '#components-demo' })`
    
    
    **组件的复用**
    你可以将组件进行任意次数的复用:
    
    
    ```

    data 必须是一个函数
    当我们定义这个 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:

    data: {
      count: 0
    }
    

    取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

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

    如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例:
    组件的组织

    通常一个应用会以一棵嵌套的组件树的形式来组织:
    例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

    为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:

    Vue.component('my-component-name', {
      // ... options ...
    })
    

    全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

    到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把组件注册读完。

    通过 Prop 向子组件传递数据
    早些时候,我们提到了创建一个博文组件的事情。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。

    Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

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

    一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

    一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来:

    <blog-post title="My journey with Vue"></blog-post>
    <blog-post title="Blogging with Vue"></blog-post>
    <blog-post title="Why Vue is so fun"></blog-post>
    

    通过事件向父级组件发送消息
    在我们开发 组件时,它的一些功能可能要求我们和父级组件进行沟通。例如我们可能会引入一个可访问性的功能来放大博文的字号,同时让页面的其它部分保持默认的字号。

    在其父组件中,我们可以通过添加一个 postFontSize 数据属性来支持这个功能:

    new Vue({
      el: '#blog-posts-events-demo',
      data: {
        posts: [/* ... */],
        postFontSize: 1
      }
    })
    
    <div id="blog-posts-events-demo">
      <div :style="{ fontSize: postFontSize + 'em' }">
        <blog-post
          v-for="post in posts"
          v-bind:key="post.id"
          v-bind:post="post"
        ></blog-post>
      </div>
    </div>
    
    Vue.component('blog-post', {
      props: ['post'],
      template: `
        <div class="blog-post">
          <h3>{{ post.title }}</h3>
          <button>
            Enlarge text
          </button>
          <div v-html="post.content"></div>
        </div>
      `
    })
    

    问题是这个按钮不会做任何事:

    <button>
      Enlarge text
    </button>
    

    当点击这个按钮时,我们需要告诉父级组件放大所有博文的文本。幸好 Vue 实例提供了一个自定义事件的系统来解决这个问题。我们可以调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件:

    <button v-on:click="$emit('enlarge-text')">
      Enlarge text
    </button>
    
    展开全文
  • Vue3中文文档

    千次阅读 2020-10-12 17:41:32
    Vue3中文文档 - vuejs https://www.vue3js.cn/docs/zh/guide/computed.html#
    展开全文
  • 详解vue axios中文文档

    2020-12-11 07:36:15
    axios中文文档 在用Vue做开发的时候,官方推荐的前后端通信插件是axios,Github上axios的文档虽然详细,但是却是英文版.现在发现有个axios的中文文档,于是就转载过来了! 原文地址 : ...
  • vue2.0中文文档

    2018-09-29 16:34:21
    vue2.0文档,希望对你们的学习有所帮助。没有资源分数的朋友可以私信我,我发给你们
  • 另外 Vue3.0 的文档也已经上线,感兴趣的小伙伴可以先睹为快。另外指路 ➡️ 之前发布过的 Vue3 的部分 API手册。概览Vue3.0 新功能Composition API----组合式 API,包括setup()等Reactivity API----响应式系统 API...

    尤大宣布 Vue3.0 已经进入候选阶段【贺电】!!!现在也可以提前试用,通过 Vite 直接初始化一个项目。另外 Vue3.0 的文档也已经上线,感兴趣的小伙伴可以先睹为快。另外指路 ➡️ 之前发布过的 Vue3 的部分 API手册。

    概览

    Vue3.0 新功能

    • Composition API----组合式 API,包括setup()
    • Reactivity API----响应式系统 API,包括ref()
    • Teleport---内置了传送组件
    • Fragments---template里可以存在多个根DOM(或组件),Vue2.x 的时候只能存在1个
    • Emits 组件中添加了自定义事件参数
    • v-model 的修改,可以传入参数,因此可以使用多个v-model,还可以自定义修饰符,移除了.sync修饰符。
    • createRenderer API from @vue/runtime-core to create custom renderers

    被移除的内容

    • 移除了keyCode修饰符,可以用kebab-case名来代替(比如.delete/.enter)
    • 移除了实例上的$on, $off$once 方法
    • 移除了过滤器Filters,Vue3.0 建议使用 computed 来实现
    • 移除了Inline templates attributes
    • 移除了.sync修饰符

    API 参考/新增以及被废弃的 API

    ---【加粗斜体代表新增,删除线~~代表移除(知乎不支持删除线,允悲),斜体代表有改动】---

    实例 API(从全局 API 拆分出来 的)

    在 Vue 3 中,会全局改变 Vue 行为的 API 移到了实例(通过 createApp 创建)的 API 中。它们只会影响该实例。 如下:mountprovideunmountdirective(自定义指令的生命周期钩子更名了)、componentconfigmixinuse

    全局 API

    createApphrender()的别名)、defineComponentdefineAsyncComponentresolveComponent(只能在渲染函数里使用)、resolveDirective(只能在渲染函数里使用)、withDirectives(只能在渲染函数里使用)、createRenderer(只能在渲染函数里使用)、nextTick、~~extend~~、~~filter~~、~~compile~~、~~observable~~(被reactive替代)、~~version~~、~~set~~

    选项

    Data

    emitsdatapropscomputedmethodswatch、~~propsData~~

    DOM

    templaterender、~~el~~、~~renderError~~

    生命周期钩子

    beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedactivateddeactivatedbeforeUnmount(~~beforeDestroy~~)、unmounted(~~destroyed~~)、errorCapturedrenderTrackedrenderTriggered

    资源

    directivescomponents、~~filters~~

    组合

    mixinsextendsprovide / injectsetup、~~parent~~

    其他

    nameinheritAttrs、~~delimiters~~、~~functional~~、~~model~~、~~comments~~

    实例属性

    $data$props$el$options$parent$root$slots$refs$attrs、~~$children~~、~~$scopedSlots~~、~~$isServer~~、~~$listeners~~

    实例方法(生命周期也被合并到这里了)

    $watch$emit$forceUpdate$nextTick、~~$set~~(文档里没有找到移除 set 的描述,用 $forceUpdate吧)、~~$delete~~、~~$mount~~、~~destroy~~

    指令

    v-textv-htmlv-showv-ifv-elsev-else-ifv-forv-onv-bindv-modelv-slotv-prev-cloakv-oncev-is(本来是通过is实现)

    特殊属性

    keyrefis、~~slot~~、~~slot-scope~~、~~scope~~(这3个在 Vue 2.6 以上就被废弃了)

    内置的组件

    componenttransitiontransition-groupkeep-aliveslotteleport

    【新增】响应式系统 API(Reactivity API )

    基本响应式 APIs

    reactivereadonlyisProxyisReactiveisReadonlytoRawmarkRawshallowReactiveshallowReadonly

    refs

    refunreftoReftoRefsisRefcustomRefshallowRef

    Computed and watch

    computedwatchEffectwatch

    【新增】组合式 API(Composition API )

    setuponBeforeMountonMountedonBeforeUpdateonUpdatedonBeforeUnmountonUnmountedonErrorCapturedonRenderTrackedonRenderTriggeredprovideinject

    以下是我对比 Vue2.x 版本文档的教程部分得出的一部分差异,欢迎补充或者提供修改建议(因为暂时还没找到中文版,所以只是自己的理解,已经在知识点上插入了文档的该部分链接,可以直接查看原文)。

    基础用法

    创建 Vue实例 的方法:

    Vue2.x 中,通过 new Vue 创建 Vue 的实例,并且通过传入 el参数 进行挂载 DOM

    <!-- Vue2.x 创建实例 -->
    var vm = new Vue({
      // 选项
    })
    
    <!-- Vue2.x 挂载DOM -->
    var vm = new Vue({
      el: '#app',
      data: {a:1}
    })

    Vue3.0 中,通过 createApp 方法创建 Vue 的实例,创建实例后可以把这个容器传给 mount 方法来挂载

    <!-- Vue3.0 创建实例 -->
    Vue.createApp(/* options */)
    
    <!-- Vue3.0 挂载DOM -->
    Vue.createApp(/* options */).mount('#app')

    生命周期

    生命周期没有太大的改变,由于创建实例的方法改变了,因此有一些细微的差别。

    值得注意的是:在 Vue2.x 中,销毁实例的两个钩子是 beforeDestory 以及 destoryed,而在 Vue3.0 中这两个钩子的名字变更为 beforeUnmountunmounted

    Vue2.x 生命周期

    4f453fb289651df80a42b1043be97827.png

    Vue3.0 生命周期

    86956bb54cb34732b98c10244ab1f282.png

    Provide / inject

    Vue3.0 在教程中添加了对Provide / inject的描述

    a668faa2a71a2787e1298949c71bef54.png

    动态组件

    Vue2.x 和 Vue3.0 都仍是采用通过给 Vue 的 元素加一个特殊的 is 属性来实现

    <!-- 组件会在 `currentTabComponent` 改变时改变 -->
    <component v-bind:is="currentTabComponent"></component>

    但是对于解析 DOM 模板,诸如<ul><table>等限制内部元素的特殊情况,相比 Vue2.x 中是通过绑定 is 属性, Vue3.0 提供的是 v-is 指令

    <!-- Vue2.x 使用 is 属性 -->
    <table>
      <tr is="blog-post-row"></tr>
    </table>
    <!-- Vue3.0 使用 v-is 指令 -->
    <table>
      <tr v-is="'blog-post-row'"></tr>
    </table>

    自定义事件

    Vue2.x 和 Vue3.0 都仍是通过$emit('myEvent')触发事件,通过v-on:myEvent来监听事件,不同的是,Vue3.0 在组件中提供了 emits 属性来定义事件

    <!-- Vue3.0 自定义事件 -->
    app.component('custom-form', {
      emits: ['in-focus', 'submit']
    })

    甚至你可以在自定义事件中添加校验,这时需要把 emits 设置为对象,并且为事件名分配一个函数,该函数接收传递给 $emit 调用的参数,并返回一个布尔值以指示事件是否有效

    <!-- Vue3.0 为自定义事件添加校验 -->
    app.component('custom-form', {
      emits: {
        // No validation
        click: null,
    
        // Validate submit event
        submit: ({ email, password }) => {
          if (email && password) {
            return true
          } else {
            console.warn('Invalid submit event payload!')
            return false
          }
        }
      },
      methods: {
        submitForm() {
          this.$emit('submit', { email, password })
        }
      }
    })

    自定义组件的 v-model

    在 Vue2.x 中, v-model 默认会利用 value 作为 prop 名以及 input 作为触发的 event 名。对于特殊的场景,也可以通过 model 选项来指定 prop 名和 event 名(注意这时仍需在 props 里声明这个 prop)

    <!-- Vue2.0 自定义 v-model -->
    Vue.component('base-checkbox', {
      model: {
        prop: 'checked',
        event: 'change'
      },
      props: {
        checked: Boolean
      },
      template: `
        <input
          type="checkbox"
          v-bind:checked="checked"
          v-on:change="$emit('change', $event.target.checked)"
        >
      `
    })

    请注意,在 Vue3.0 中, v-model 默认会利用 modelValue 作为 prop 名以及 update:modelValue 作为触发的 event 名。

    支持给每个 v-model 传入一个参数,这样就可以在一个组件上同时使用多个 v-model

    <!-- Vue3.0 自定义 v-model 并且传入参数 -->
    <my-component v-model:foo="bar" v-model:name="userName"></my-component>

    甚至还可以为 v-model 设置自定义修饰符,默认是通过在props中定义 modelModifiers 对象来接受修饰符,因此你可以通过修饰符来设置你想要的不同的事件触发机制

    <!-- Vue3.0 自定义修饰符默认接收方式 -->
    <div id="app">
      <my-component v-model.capitalize="myText"></my-component>
      {{ myText }}
    </div>
    
    const app = Vue.createApp({
      data() {
        return {
          myText: ''
        }
      }
    })
    
    app.component('my-component', {
      props: {
        modelValue: String,
        modelModifiers: {
          default: () => ({})
        }
      },
      methods: {
        emitValue(e) {
          let value = e.target.value
          if (this.modelModifiers.capitalize) {
            value = value.charAt(0).toUpperCase() + value.slice(1)
          }
          this.$emit('update:modelValue', value)
        }
      },
      template: `<input
        type="text"
        v-bind:value="modelValue"
        v-on:input="emitValue">`
    })
    
    app.mount('#app')

    当然,对于传入了参数的 v-model ,则需要在props里面配置arg + "Modifiers"来接收这个带参数的 v-model 的修饰符

    <!-- Vue3.0 自定义参数的自定义修饰符 -->
    <my-component v-model:foo.capitalize="bar"></my-component>
    
    app.component('my-component', {
      props: ['foo', 'fooModifiers'],
      template: `
        <input type="text" 
          v-bind:value="foo"
          v-on:input="$emit('update:foo', $event.target.value)">
      `,
      created() {
        console.log(this.fooModifiers) // { capitalize: true }
      }
    })

    混入 (mixin)

    Vue2.x 混入的方式 通过 Vue.extend({mixins: [myMixin]}) 定义一个使用混入对象的组件

    // 定义一个混入对象
    var myMixin = {
      created: function () {
        this.hello()
      },
      methods: {
        hello: function () {
          console.log('hello from mixin!')
        }
      }
    }
    
    // 定义一个使用混入对象的组件
    var Component = Vue.extend({
      mixins: [myMixin]
    })
    
    var component = new Component() // => "hello from mixin!"

    而 Vue3.0 则和创建一个实例相似,通过 Vue.createApp({mixins: [myMixin]}) 定义一个使用混入对象的组件

    // 定义一个混入对象
    const myMixin = {
      created() {
        this.hello()
      },
      methods: {
        hello() {
          console.log('hello from mixin!')
        }
      }
    }
    
    // 定义一个使用混入对象的组件
    const app = Vue.createApp({
      mixins: [myMixin]
    })
    
    app.mount('#mixins-basic') // => "hello from mixin!"

    自定义指令

    Vue2.x 的指令定义对象包含 5 个钩子:

    • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
    • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
    • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    • unbind:只调用一次,指令与元素解绑时调用。

    Vue3.0 的指令对象包含 6 个钩子:

    • beforeMount:指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    • mounted:当被绑定元素插入父节点时调用。
    • beforeUpdate:在更新所在组件的VNode之前调用。
    • updated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    • beforeUnmount:在绑定元素的父组件卸载之前调用。(对比 Vue2.x 新增
    • unmounted:只调用一次,指令与元素解绑且父组件已卸载时调用。

    在 Vue3.0 中,由于对片段的支持,组件可能会存在多个根节点,这时使用自定义指令可能会产生问题。自定义指令对象包含的钩子会被包装并作为 Vnode 生命周期钩子注入到 Vnode 的数据中。

    <!-- Vue3.0 自定义指令对象包含的钩子包装后 -->
    {
      onVnodeMounted(vnode) {
        // call vDemo.mounted(...)
      }
    }

    当在组件中使用自定义指令时,这些onVnodeXXX钩子将作为无关属性直接传递给组件,可以像这样在模板中直接挂接到元素的生命周期中(这里不太明白,之后试验过再来更新)

    <div @vnodeMounted="myHook" />

    当子组件在内部元素上使用 v-bind="$attrs" 时,它也将应用它上面的任何自定义指令。

    内置的传送组件 Teleport

    Vue3.0 内置<teleport>的组件可以传送一段模板到其他位置,

    <!-- Vue3.0 <teleport>传送组件 -->
    <body>
      <div id="app" class="demo">
        <h3>Move the #content with the portal component</h3>
        <div>
          <teleport to="#endofbody">
            <p id="content">
              This should be moved to #endofbody.
            </p>
          </teleport>
          <span>This content should be nested</span>
        </div>
      </div>
      <div id="endofbody"></div>
    </body>

    如果<teleport>包含Vue组件,它将仍然是<teleport>父组件的逻辑子组件,也就是说,即使在不同的地方呈现子组件,它仍将是父组件的子组件,并将从父组件接收 prop

    使用多个传送组件 会采用累加的逻辑,像这样

    <teleport to="#modals">
      <div>A</div>
    </teleport>
    <teleport to="#modals">
      <div>B</div>
    </teleport>
    
    <!-- 结果 B 渲染在 A 后面 -->
    <div id="modals">
      <div>A</div>
      <div>B</div>
    </div>

    渲染函数

    Vue2.x 的渲染函数的参数是createElement

    Vue3.0 的渲染函数的参数createVNode(这个名字更接近它实际的意义,返回虚拟 DOM)

    同样将h作为别名,在 Vue3.0 中可以直接通过 Vue.h 获取

    const app = Vue.createApp({})
    
    app.component('anchored-heading', {
      render() {
        const { h } = Vue
    
        return h(
          'h' + this.level, // tag name
          {}, // props/attributes
          this.$slots.default() // array of children
        )
      },
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    })

    事件 & 按键修饰符 Vue2.x 对于 .passive、.capture 和 .once 这些事件修饰符,提供了相应的前缀可以用于 on:、 | 修饰符 | 前缀 |------|------------ | .passive | &
    | .capture | !
    | .once | ~ | .capture.once.once.capture | ~!

    <!-- Vue2.x 对修饰符使用前缀 -->
    on: {
      '!click': this.doThisInCapturingMode,
      '~keyup': this.doThisOnce,
      '~!mouseover': this.doThisOnceInCapturingMode
    }

    而 Vue3.0 则是使用对象语法

    <!-- Vue3.0 对修饰符使用对象语法 -->
    render() {
      return Vue.h('input', {
        onClick: {
          handler: this.doThisInCapturingMode,
          capture: true
        },
        onKeyUp: {
          handler: this.doThisOnce,
          once: true
        },
        onMouseOver: {
          handler: this.doThisOnceInCapturingMode,
          once: true,
          capture: true
        },
      })
    }

    插件

    开发插件 Vue3.0 仍需要暴露一个 install方法,传入两个参数,第一个参数是通过Vue.createApp构造的对象,第二个可选参数是用户传入的options

    // plugins/i18n.js
    export default {
      install: (app, options) => {
      // Plugin code goes here
      }
    }

    插件中通过暴露出的app.config.globalProperties属性注册全局方法

    // plugins/i18n.js
    <!-- 通过 app.config.globalProperties 全局注入 translate 方法 -->
    export default {
      install: (app, options) => {
        app.config.globalProperties.$translate = (key) => {
          return key.split('.')
            .reduce((o, i) => { if (o) return o[i] }, i18n)
        }
      }
    }

    还可以通过inject来为用户提供方法或属性

    // plugins/i18n.js
    <!-- 这样组件里就可以通过 inject 访问 i18n 和 options -->
    export default {
      install: (app, options) => {
        app.config.globalProperties.$translate = (key) => {
          return key.split('.')
            .reduce((o, i) => { if (o) return o[i] }, i18n)
        }
    
        app.provide('i18n')
      }
    }
    
    <!-- 然后就可以通过 inject['i18n'] 把 i18n 注入组件并访问 -->

    使用插件 仍然是通过 use() 方法,可以接受两个参数,第一个参数是要使用的插件,第二个参数可选,会传入到插件中去。

    import { createApp } from 'vue'
    import App from './App.vue'
    import i18nPlugin from './plugins/i18n'
    
    const app = createApp(App)
    const i18nStrings = {
      greetings: {
        hi: 'Hallo!'
      }
    }
    
    app.use(i18nPlugin, i18nStrings)
    app.mount('#app')

    响应式原理

    响应式系统

    众所周知,Vue2.x 是通过 Object.defineProperty结合订阅/发布模式实现的。

    给 Vue 实例传入 data 时,Vue 将遍历data 对象所有的 property,并使用 Object.defineProperty 把这些属性全部转为 getter/setter,在属性被访问和修改时追踪到依赖。每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

    ed3fd0b43da2f8ad015bf05e76889304.png

    、 而 Vue3.0 则是采用 ES6 的 Proxy 代理来拦截对目标对象的访问。 给 Vue 实例传入 data 时,Vue 会将其转换为Proxy。它能使 Vue 在访问或修改属性时执行依赖追踪以及更改通知。每个属性都被视为一个依赖项。 在初次渲染后,组件将追踪依赖(也就是它在渲染时访问过的属性)。换句话说,组件成为这些属性的订阅者。当代理拦截到 set 操作时,该属性将通知其订阅者重新渲染。

    const dinner = {
      meal: 'tacos'
    }
    
    const handler = {
      get(target, prop, receiver) {
        track(target, prop) // Track the function that changes it 依赖项跟踪
        return Reflect.get(...arguments)
      },
      set(target, key, value, receiver) {
        trigger(target, key) // Trigger the function so it can update the final value 更改通知
        return Reflect.set(...arguments)
      }
    }
    
    const proxy = new Proxy(dinner, handler)
    console.log(proxy.meal)
    
    // intercepted!
    // tacos

    值得注意的是,原始对象与代理对象是不相等

    const obj = {}
    const wrapped = new Proxy(obj, handlers)
    console.log(obj === wrapped) // false

    响应式基础原理 Reactivity Fundamentals

    声明响应式状态reactive

    reactive方法接收一个普通对象作为参数,然后返回该普通对象的响应式代理(等同于 Vue2.x 中的 Vue.observable() )以创建一个响应式属性。响应式转换是“深层的”,返回的代理对象不等于原始对象。模板编译的过程中 render 方法用的就是这些响应式属性。

    import { reactive } from 'vue'
    
    // reactive state
    const state = reactive({
      count: 0
    })

    还可以创建只读的响应式属性,也是深层的,对象内部任何嵌套的属性也都是只读的。

    const original = reactive({ count: 0 })
    
    const copy = readonly(original)
    
    // mutating original will trigger watchers relying on the copy
    original.count++
    
    // mutating the copy will fail and result in a warning
    copy.count++ // warning: "Set operation on key 'count' failed: target is readonly."

    创建独立的响应式属性refs

    ref方法接受一个原始值参数,同样也会返回一个响应式的可变 ref 对象。如果是原始类型的值,由于原始类型的值是按值传递而不是按引用传递,会像是把原始类型的值包装成了一个对象一样以保证响应式,但这个对象只包含唯一的属性value。而对于引用类型,则会调用 reactive 方法进行深层响应转换。

    import { ref } from 'vue'
    
    const count = ref(0)
    console.log(count.value) // 0
    
    count.value++
    console.log(count.value) // 1

    当一个ref作为在渲染上下文中返回的属性且在模板中被访问时,会自动解套内部的value,因此无需再使用xx.value的方式来访问,这样就像访问一个普通属性一样。要注意,自动解套 value 只发生在当嵌套响应式的对象中时,从数组或Map等原生集合类中访问时不会自动解套,仍需要.value

    <template>
      <div>
        <span>{{ count }}</span>
        <button @click="count ++">Increment count</button>
      </div>
    </template>
    
    <script>
      import { ref } from 'vue'
      export default {
        setup() {
          const count = ref(0)
          return {
            count
          }
        }
      }
    </script>

    另外如果将一个新的ref赋值给现有的属性,那将替换掉旧的ref

    const otherCount = ref(2)
    
    state.count = otherCount
    console.log(state.count) // 2
    console.log(count.value) // 1

    计算

    computed方法

    通过computed方法可以直接创建一个计算值,接收一个getter函数作为参数并且返回一个不可手动修改的响应式对象。

    const count = ref(1)
    const plusOne = computed(() => count.value++)
    
    console.log(plusOne.value) // 2
    
    plusOne.value++ // error

    或者可以传入一个带有gettersetter方法的对象来创建一个可以手动修改的响应式对象

    const count = ref(1)
    const plusOne = computed({
      get: () => count.value + 1,
      set: val => {
        count.value = val - 1
      }
    })
    
    plusOne.value = 1
    console.log(count.value) // 0

    监听

    watchEffect方法

    watchEffect方法它可以侦听依赖,它会立即运行传入的函数,并且跟踪这个函数的依赖项,当依赖项更新时,立即再次执行这个函数。

    const count = ref(0)
    
    watchEffect(() => console.log(count.value))
    // -> logs 0
    
    setTimeout(() => {
      count.value++
      // -> logs 1
    }, 100)

    watchEffect在组件的setup()或生命周期钩子中被调用时,侦听器会自动链接到该组件的生命周期,并且在组件卸载时自动停止。或者可以通过显式调用watchEffect的返回值以停止侦听。

    const stop = watchEffect(() => {
      /* ... */
    })
    Vue3
    // 之后
    stop()

    Side Effect Invalidation 清除副作用

    有时watchEffect中执行的方法可能是异步的,watchEffect传入的函数可以接收一个onInvalidate函数作为参数来注册清理失效时的回调,它将会在watchEffect重新执行时或者watchEffect被终止(如果在setup()生命周期钩子中使用了watchEffect,则在组件卸载时)时执行。

    watchEffect(onInvalidate => {
      const token = performAsyncOperation(id.value)
      onInvalidate(() => {
        // id 改变时 或 停止侦听时
        // 取消之前的异步操作
        token.cancel()
      })
    })

    注意setup()将在组件挂载前调用,因此如果想要在watchEffect中使用 DOM (或者组件),请在挂载的钩子中声明watchEffect

    onMounted(() => {
      watchEffect(() => {
        // access the DOM or template refs
      })
    })

    还可以为watchEffect传入额外的对象作为参数。 比如通过设置flush来设置watchEffect是异步执行还是在组件更新前执行

    // 同步运行
    watchEffect(
      () => {
        /* ... */
      },
      {
        flush: 'sync'
      }
    )
    
    // 组件更新前执行
    watchEffect(
      () => {
        /* ... */
      },
      {
        flush: 'pre'
      }
    )

    onTrack(追踪依赖时调用)和onTrigger(依赖改变触发了watchEffect的方法时触发)参数可以用来调试watchEffect的行为

    watchEffect(
      () => {
        /* side effect */
      },
      {
        onTrigger(e) {
          debugger
        }
      }
    )

    watch相比watchEffect,watch是惰性的,更明确哪些状态的改变会触发侦听器重新运行,并且可以访问被侦听属性的变化前后的值。

    // 侦听一个 getter
    const state = reactive({ count: 0 })
    watch(
      () => state.count,
      (count, prevCount) => {
        /* ... */
      }
    )
    
    // 直接侦听一个 ref
    const count = ref(0)
    watch(count, (count, prevCount) => {
      /* ... */
    })
    // 侦听多个数据源
    watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
      /* ... */
    })

    组合式 API(Composition API)

    在正常的业务中我们常常会抽离可复用的组件,比如过滤功能、搜索功能、业务列表等等。但是当某个组件组合得很庞大时,需要关注的逻辑列表(引入的组件)也会相应的增加,这可能导致难以阅读和理解,尤其对于那些最初没有编写它们的人。因此我们想要组合起与逻辑有关系的代码,这也时Composition API 的用途。

    <!-- 没有 Composition API 时我们通常这样做 -->
    <!-- 将逻辑关系标记为相同的数字 -->
    
    // src/components/UserRepositories.vue
    
    export default {
      components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
      props: {
        user: { type: String }
      },
      data () {
        return {
          repositories: [], // 1
          filters: { ... }, // 3
          searchQuery: '' // 2
        }
      },
      computed: {
        filteredRepositories () { ... }, // 3
        repositoriesMatchingSearchQuery () { ... }, // 2
      },
      watch: {
        user: 'getUserRepositories' // 1
      },
      methods: {
        getUserRepositories () {
          // using `this.user` to fetch user repositories
        }, // 2
        updateFilters () { ... }, // 3
      },
      mounted () {
        this.getUserRepositories() // 1
      }
    }

    setup 组件参数

    setup 是一个新的组件参数,在组件内使用并且作为 Composition API 的入口点。

    setup方法接受2个参数。 第一个参数是 props ,它在 setup 内部也是响应式的(注意不要对 props 直接使用解构赋值,这样会破坏响应式,但是可以使用 toRefs来实现安全的解构)。

    // MyBook.vue
    
    import { toRefs } from 'vue'
    
    setup(props) {
        const { title } = toRefs(props)
    
        console.log(title.value)
    }

    第二个参数是 context ,它是一个普通的对象(不是响应式的)并且暴露出3个组件属性。

    // MyBook.vue
    
    export default {
      setup(props, context) {
        // Attributes (Reactive Property)
        console.log(context.attrs)
    
        // Slots (Reactive Property)
        console.log(context.slots)
    
        // Emit Events (Method)
        console.log(context.emit)
      }
    }

    setup会在组件实例创建前,props初始化后被执行,因此只能访问 propsattrsslotsemit,而无权访问组件内部的 datacomputedmethods。注意setup()内部的this不会是Vue的实例的引用。

    setup可以返回一个对象,它的所有属性都将暴露给其他的组件选项( computed 的属性、 methods 、生命周期钩子等)以及组件模板。也可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态:

    Composition API 也包含了类似组件参数的生命周期钩子函数,但会以前缀为 onXXX 这样的名字,像是 mounted 对应的是 onMounted,接受一个回调,这个回调会在组件的钩子被调用时执行。 | Options API | setup 里的钩子 | | ----------------- | ------------------------ | | beforeCreate | 不需要 | | created | 不需要 | | beforeMount | onBeforeMountonMounted | | mounted | onMounted | | beforeUpdate | onBeforeUpdate | | updated | onUpdated | | beforeUnmount | onBeforeUnmount | | unmounted | onUnmounted | | errorCaptured | onErrorCaptured | | renderTracked | onRenderTracked | | renderTriggered | onRenderTriggered | 由于 setup 是围绕 beforeCreatecreated 生命周期钩子运行的,也就是说将在这两个钩子中编写的任何代码都应该直接在 setup 中编写。

    Composition API 还包含 watch 方法,接受3个参数,第一个参数是一个我们要真侦听的响应式对象或者包含getter的函数,第二个参数是一个回调,第三个参数是可选的配置选项。

    还有前文提到的 Composition APIcomputed 方法可以在组件外部创建一个计算属性

    因此我们可以把上面的栗子重写成这样,无论何时我们调用 getUserRepositories 方法,repositories 都会响应式地进行改变,视图也将更新。

    // src/composables/useUserRepositories.js
    
    import { fetchUserRepositories } from '@/api/repositories'
    import { ref, onMounted, watch, toRefs } from 'vue'
    
    export default function useUserRepositories(user) {
      // 数据列表(创建一个响应式对象)
      const repositories = ref([])
    
      // 更新数据列表的方法
      const getUserRepositories = async () => {
        repositories.value = await fetchUserRepositories(user.value)
      }
    
      onMounted(getUserRepositories)
    
      // 在 user 上设置一个侦听器
      watch(user, getUserRepositories)
    
      // 返回列表和方法,以在其他组件选项中访问它们
      return {
        repositories,
        getUserRepositories
      }
    }
    
    
    // src/components/UserRepositories.vue
    // 在组件中引入 useUserRepositorie), useRepositoryNameSearch和 useRepositoryFilters
    import { toRefs } from 'vue'
    import useUserRepositories from '@/composables/useUserRepositories'
    import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
    import useRepositoryFilters from '@/composables/useRepositoryFilters'
    
    export default {
      components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
      props: {
        user: { type: String }
      },
      setup(props) {
        const { user } = toRefs(props)
    
        const { repositories, getUserRepositories } = useUserRepositories(user)
    
        const {
          searchQuery,
          repositoriesMatchingSearchQuery
        } = useRepositoryNameSearch(repositories)
    
        const {
          filters,
          updateFilters,
          filteredRepositories
        } = useRepositoryFilters(repositoriesMatchingSearchQuery)
    
        return {
          // 只关心过滤后的结果,因此可以以 repositories 这样的名称暴露出去
          repositories: filteredRepositories,
          getUserRepositories,
          searchQuery,
          filters,
          updateFilters
        }
      }
    }

    setup中还可以使用 provide / inject ,甚至可以 provide 一个响应式状态,注意因为单向数据流,所以不要在 inject 时注入为响应式状态,而是在provide时就提供为响应式状态。

    import { ref, reactive } from 'vue'
    
    // in provider
    setup() {
      const book = reactive({
        title: 'Vue 3 Guide',
        author: 'Vue Team'
      })
      const year = ref('2020') // 也可以提供一个响应式状态,尽量在provide时注入为响应式状态
    
      provide('book', book)
      provide('year', year) // 如果要提供多个值,可以之后再次调用 provide
    }
    
    // in consumer
    setup() {
      const book = inject('book', 'Eloquent Javasctipt') /* 可选的参数默认值 */
      const year = inject('year') 
    
      return { book, year }
    }

    setup 中, 响应式 refs 和模板的 refs 是统一的,为了获得对模板内元素或组件实例的引用,可以在 setup 声明一个 ref 并返回它。像这样我们将 root 暴露在渲染上下文中并通过 ref="root" 将绑定到 div 作为其 ref 。在虚拟 DOM 算法中如果虚拟节点的 ref 对应上了渲染上下文的 ref,那么就会把虚拟节点对应的元素或者组件实例分配给这个 ref,这是在虚拟 DOM 挂载或修改时执行的,因此模板 ref 仅在渲染初始化后才能访问。

    <template>
      <div ref="root">This is a root element</div>
      <div v-for="(item, i) in list" :ref="el => { divs[i] = el }">
        {{ item }}
      </div>
    </template>
    
    <script>
      import { ref, onMounted } from 'vue'
    
      export default {
        setup() {
          const root = ref(null)
          const divs = ref([])
    
          onMounted(() => {
            // 在初始化后 DOM 元素将会被分配给 ref
            console.log(root.value) // <div>This is a root element</div>
          })
          // 在每次更新前重置引用
          onBeforeUpdate(() => {
            divs.value = []
          })
    
          return {
            root,
            divs
          }
        }
      }
    </script>

    响应式系统工具集

    unref

    如果参数是一个 ref 则返回它的 value,否则返回参数本身。它是 val = isRef(val) ? val.value : val 的语法糖。

    function useFoo(x: number | Ref<number>) {
      const unwrapped = unref(x) // unwrapped 一定是 number 类型
    }

    toRef

    toRef 可以用来为一个 reactive 对象的属性创建一个 ref。这个 ref 可以被传递并且能够保持响应性。当您要将一个 prop 中的属性作为 ref 传给组合逻辑函数时,toRef 就派上了用场。

    const state = reactive({
      foo: 1,
      bar: 2,
    })
    
    const fooRef = toRef(state, 'foo')
    
    fooRef.value++
    console.log(state.foo) // 2
    
    state.foo++
    console.log(fooRef.value) // 3

    toRefs

    把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref ,和响应式对象 property 一一对应。当想要从一个组合逻辑函数中返回响应式对象时,用 toRefs 是很有效的,该 API 让消费组件可以 解构 / 扩展(使用 ... 操作符)返回的对象,并不会丢失响应性。

    isRef

    检查一个值是否为一个 ref 对象。

    isProxy

    检查一个对象是否是由 reactive 或者 readonly 方法创建的代理。

    isReactive

    检查一个对象是否是由 reactive 创建的响应式代理。如果这个代理是由 readonly 创建的,但是又被 reactive 创建的另一个代理包裹了一层,那么同样也会返回 true

    isReadonly

    检查一个对象是否是由 readonly 创建的只读代理。

    const state = reactive({
      foo: 1,
      bar: 2,
    })
    
    const stateAsRefs = toRefs(state)
    /*
    stateAsRefs 的类型如下:
    
    {
      foo: Ref<number>,
      bar: Ref<number>
    }
    */
    
    // ref 对象 与 原属性的引用是 "链接" 上的
    state.foo++
    console.log(stateAsRefs.foo) // 2
    
    stateAsRefs.foo.value++
    console.log(state.foo) // 3

    高级响应式系统 API

    customRef

    customRef 用于自定义一个 ref,可以显式地控制依赖追踪和触发响应,接受一个工厂函数,两个参数分别是用于追踪的 track 与用于触发响应的 trigger,并返回一个一个带有 getset 属性的对象 这是一个使用自定义 ref 实现带防抖功能的 v-model的栗子

    <input v-model="text" />
    
    function useDebouncedRef(value, delay = 200) {
      let timeout
      return customRef((track, trigger) => {
        return {
          get() {
            track()
            return value
          },
          set(newValue) {
            clearTimeout(timeout)
            timeout = setTimeout(() => {
              value = newValue
              trigger()
            }, delay)
          },
        }
      })
    }
    
    export default {
      setup() {
        return {
          text: useDebouncedRef('hello'),
        }
      },
    }

    markRaw

    显式标记一个对象为“永远不会转为响应式代理”,函数返回这个对象本身。

    shallowReactive

    只为某个对象的私有(第一层)属性创建浅层的响应式代理,不会对“属性的属性”做深层次、递归地响应式代理,而只是保留原样。

    shallowReadonly

    只为某个对象的自有(第一层)属性创建浅层的只读响应式代理,同样也不会做深层次、递归地代理,深层次的属性并不是只读的。

    shallowRef

    创建一个 ref ,将会追踪它的 .value 更改操作,但是并不会对变更后的 .value 做响应式代理转换(即变更不会调用 reactive

    toRaw

    返回由 reactivereadonly 方法转换成响应式代理的普通对象。这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发更改。不建议一直持有原始对象的引用。请谨慎使用。


    以上是对比教程上的内容找出的差异,最重要的就是 Composition APIReactivity 也是我觉得最难的部分。另外 Vue3.0 的文档仍处于开发中,后续可能还会有一些改动,请以文档为准,还没有直接上手进行开发,因此没有提出太多个人见解,仅作为与 Vue2.x 的对比。

    展开全文
  • Vue.js中文文档

    2016-11-09 08:17:59
    Vue.js中文文档
  • vue 相关中文文档

    2019-09-26 08:48:58
    https://github.com/vuejs/vue-docs-zh-cn 转载于:https://www.cnblogs.com/heroljy/p/10149033.html
  • Vue3中文文档 - vuejs

    2021-03-04 21:00:32
    [Vue3中文文档 - vuejs](https://vue3js.cn/docs/zh/guide/introduction.html#%E8%B5%B7%E6%AD%A5)
  • vue.js 中文文档 1.0

    2016-09-22 14:17:40
    vue.js 中文文档 1.0
  • vue2.0中文文档

    2019-04-30 15:10:00
    地址1: 链接: https://pan.baidu.com/s/1uEzM990A-W-fl23ref2zww 提取码: rkpt 复制这段内容后打开百度网盘手机App,操作更方便哦 地址2:https://pan.baidu.com/s/1eSoir1C 转载于:...
  • vue3中文文档地址

    2020-11-18 10:22:49
    https://vue3js.cn/docs/zh/
  • Vue3.0 中文文档:https://www.vue3js.cn/docs/zh/ Vue3.0 组合API使用:http://www.liulongbin.top:8085/#/ Vue3.0 Vuex 替代方案: https://zhuanlan.zhihu.com/p/114783130 B站视频学习: 尤雨溪Vue3.0 : ...
  • Vue-axios中文文档

    2019-12-27 09:15:13
    Vue-axios官方文档 官方文档 axios
  • vue axios中文文档详解

    2019-04-25 08:50:00
    英文文档:https://github.com/axios/axios 参考:https://www.jb51.net/article/123485.htm 转载于:https://www.cnblogs.com/yingyigongzi/p/10766267.html
  • vue.js 中文文档1.0

    2017-12-27 10:21:15
    vue.js小书 尤雨溪推荐 重点讲解抽离出官方文档中重要的内容 Vue.js是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,并且非常容易学习,...
  • Vue3.0中文地址文档

    2020-12-24 15:56:15
    vue3.0中文地址 最新vue3.0中文地址 https://v3.cn.vuejs.org/guide/introduction.html
  • vue中文版Dash文档

    千次阅读 2019-12-03 23:08:18
    文章目录 准备 开始 导入 准备 node 环境 ...wget --mirror -p --convert-links -P [本地路径] [要扒的网址] ...使用NodeJS 生成Vue中文版 docSet 离线文档 kapeli.com/docsets官方制作教程
  • Vue CLI 3 中文文档

    千次阅读 2018-11-07 13:47:00
    之前写了一篇Vue CLI 3.x 版本的简单体验,当时文档还不全,具体的使用方法并不是很清楚,大概是2月7号,收到Vue CLI 3接近Beta版的提示,作者尤雨溪也讲下周会出文档,没想到昨天已经出来了。本着对新功能的好奇心...
  • vue.js官方中文文档

    2020-11-02 22:25:42
    vue.js官方中文文档https://vuejs.bootcss.com/guide/
  • vue-resource中文文档

    2018-10-12 13:06:00
    Vue可以构建一个完全不依赖后端服务的应用,同时也可以与服务端进行数据交互来同步界面的动态更新。 Vue通过插件的形式实现了基于AJAX,JSPNP等技术的服务端通信。 vue-resource是一个通过XMLHttpRequrest或JSONP...
  • https://vue-docs-next-zh-cn.netlify.app/guide/installation.html#vue-devtools https://www.vue3js.cn/docs/zh/
  • cn.vuejs.org同步dash文档Vue版本为2.6.10,更新时间2019/9/22

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,515
精华内容 606
关键字:

vue中文文档

vue 订阅