XingYun blog
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具

XingYun

冲!
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具
  • 3个提升Vue性能的写法
  • 重读Vue文档
    • moment.js给定时间获取自然月、周的时间轴
    • Vue虚拟dom与Diff算法
    • 深入响应式原理
    • Echart样例
    • 我的Vue指令库
    • 滚动到底部加载更多
    • 实现一键换肤
    • 手写Vue数据劫持
    • vue-router核心原理与手写实现
    • computed和watch
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
    • webpack loader和plugin
    • keep-alive组件原理
    • vue插槽进化
    • Vue多层嵌套组件
    • vue生命周期hook
    • vue监听dom元素的resize事件
    • 前端打包需要gzip压缩吗
    • 实现水波浪进度球
    • Vue
    XingYun
    2022-02-10
    目录

    重读Vue文档

    我觉得读官方文档是最好的学习方式之一, 之前读 Vue 文档比较浅显, 现在结合 Vue 源码补一补。

    下面记录一些重要的知识点

    # 2.6.0 新增动态参数绑定

    从 2.6.0 开始,可以用方括号括起来的 JavaScript 表达式作为一个指令的参数:

    <a :[attributeName]="url"> ... </a>
    
    <a @[event]="doSomething"> ... </a>
    
    1
    2
    3

    双变量可以让参数绑定更加灵活

    注意: 动态参数预期会求出一个字符串,异常情况下值为 null。这个特殊的 null 值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。

    # 计算属性是基于它们的响应式依赖进行缓存的

    两个关键特性:

    1. 计算属性的结果基于它们内部依赖的值,依赖的值发生变化,计算属性结果也会改变
    2. 多次访问计算属性, 计算属性会立即返回之前的计算结果,而不必再次执行函数, 只在相关响应式依赖发生改变时它们才会重新求值

    # 用 v-for 遍历对象的 key value

    你也可以用 v-for 来遍历一个对象的 key 和 value。

    <div v-for="(value, name) in object">
      {{ name }}: {{ value }}
    </div>
    
    1
    2
    3
    new Vue({
      el: '#v-for-object',
      data: {
        object: {
          title: 'How to do lists in Vue',
          author: 'Jane Doe',
          publishedAt: '2016-04-10'
        }
      }
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    结果:

    title: How to do lists in Vue
    author: Jane Doe
    publishedAt: 2016-04-10

    在遍历对象时,会按 Object.keys() 的结果遍历, 它的顺序不稳定, 且不能保证它的结果在不同的 JavaScript 引擎下都一致。

    # $event 访问原始的 DOM 事件

    <input @keydown="test($event)" />
    
    1
      test(e) {
        console.log(e)
      }
    
    1
    2
    3

    如下

    可以查看到具体的事件信息,不同的 html 包含的事件种类不同

    # 为什么在 HTML 中监听事件?

    你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:

    1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。

    2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。

    3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。

    # v-model 修饰符

    .lazy

    在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:

    <!-- 在“change”时而非“input”时更新 -->
    <input v-model.lazy="msg" />
    
    1
    2

    .number

    如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

    <input v-model.number="age" type="number" />
    
    1

    这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

    .trim

    如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

    <input v-model.trim="msg" />
    
    1

    # 单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

    额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

    这里有两种常见的试图变更一个 prop 的情形:

    1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop

    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
    
    1
    2
    3
    4
    5
    6

    这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:

    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }
    
    1
    2
    3
    4
    5
    6

    注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

    # prop 类型检查

    type 可以是下列原生构造函数中的一个:

    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol

    额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:

    function Person(firstName, lastName) {
      this.firstName = firstName
      this.lastName = lastName
    }
    
    1
    2
    3
    4

    你可以使用:

    Vue.component('blog-post', {
      props: {
        author: Person
      }
    })
    
    1
    2
    3
    4
    5

    来验证 author prop 的值是否是通过 new Person 创建的。

    # 将原生事件绑定到组件

    你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符:

    <base-input v-on:focus.native="onFocus"></base-input>
    
    1

    在有的时候这是很有用的,不过在你尝试监听一个类似 input 的非常特定的元素时,这并不是个好主意。比如上述 base-input 组件可能做了如下重构,所以根元素实际上是一个 label 元素:

    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
      />
    </label>
    
    1
    2
    3
    4
    5
    6
    7
    8

    这时,父级的 .native 监听器将静默失败。它不会产生任何报错,但是 onFocus 处理函数不会如你预期地被调用。

    为了解决这个问题,Vue 提供了一个 $listeners property,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:

    {
      focus: function (event) { /* ... */ }
      input: function (value) { /* ... */ },
    }
    
    1
    2
    3
    4

    有了这个 $listeners property,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。对于类似 input 的你希望它也可以配合 v-model 工作的组件来说,为这些监听器创建一个类似下述 inputListeners 的计算属性通常是非常有用的:

    Vue.component('base-input', {
      inheritAttrs: false,
      props: ['label', 'value'],
      computed: {
        inputListeners: function() {
          var vm = this
          // `Object.assign` 将所有的对象合并为一个新对象
          return Object.assign(
            {},
            // 我们从父级添加所有的监听器
            this.$listeners,
            // 然后我们添加自定义监听器,
            // 或覆写一些监听器的行为
            {
              // 这里确保组件配合 `v-model` 的工作
              input: function(event) {
                vm.$emit('input', event.target.value)
              }
            }
          )
        }
      },
      template: `
        <label>
          {{ label }}
          <input
            v-bind="$attrs"
            v-bind:value="value"
            v-on="inputListeners"
          >
        </label>
      `
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

    现在 base-input 组件是一个完全透明的包裹器了,也就是说它可以完全像一个普通的 input 元素一样使用了:所有跟它相同的 attribute 和监听器都可以工作,不必再使用 .native 监听器。

    # .sync 修饰符

    2.3.0+ 新增

    在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。

    这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

    this.$emit('update:title', newTitle)
    
    1

    然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:

    <text-document
      v-bind:title="doc.title"
      v-on:update:title="doc.title = $event"
    ></text-document>
    
    1
    2
    3
    4

    为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

    <text-document v-bind:title.sync="doc.title"></text-document>
    
    1

    注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model。

    当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

    <text-document v-bind.sync="doc"></text-document>
    
    1

    这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

    将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。

    所以最好的用法是绑定一个对象或计算属性

    # 事件侦听器监听 hook 事件

    现在,你已经知道了 $emit 的用法,它可以被 v-on 侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法。我们可以:

    通过 $on(eventName, eventHandler) 侦听一个事件
    通过 $once(eventName, eventHandler) 一次性侦听一个事件
    通过 $off(eventName, eventHandler) 停止侦听一个事件

    你通常不会用到这些,但是当你需要在一个组件实例上手动侦听事件时,它们是派得上用场的。它们也可以用于代码组织工具。例如,你可能经常看到这种集成一个第三方库的模式:

    // 一次性将这个日期选择器附加到一个输入框上
    // 它会被挂载到 DOM 上。
    mounted: function () {
      // Pikaday 是一个第三方日期选择器的库
      this.picker = new Pikaday({
        field: this.$refs.input,
        format: 'YYYY-MM-DD'
      })
    },
    // 在组件被销毁之前,
    // 也销毁这个日期选择器。
    beforeDestroy: function () {
      this.picker.destroy()
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    这里有两个潜在的问题:

    1. 它需要在这个组件实例中保存这个 picker,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。
    2. 我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。

    你应该通过一个程序化的侦听器解决这两个问题:

      mounted: function () {
      var picker = new Pikaday({
        field: this.$refs.input,
        format: 'YYYY-MM-DD'
      })
    
      this.$once('hook:beforeDestroy', function () {
        picker.destroy()
      })
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    使用了这个策略,我甚至可以让多个输入框元素同时使用不同的 Pikaday,每个新的实例都程序化地在后期清理它自己:

    mounted: function () {
      this.attachDatepicker('startDateInput')
      this.attachDatepicker('endDateInput')
    },
    methods: {
      attachDatepicker: function (refName) {
        var picker = new Pikaday({
          field: this.$refs[refName],
          format: 'YYYY-MM-DD'
        })
    
        this.$once('hook:beforeDestroy', function () {
          picker.destroy()
        })
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    注意 Vue 的事件系统不同于浏览器的 EventTarget API。尽管它们工作起来是相似的,但是 $emit、$on, 和 $off 并不是 dispatchEvent、addEventListener 和 removeEventListener 的别名。

    这里通过 this.$once('hook:beforeDestroy', function () { }) 方法也可以清除一些定时任务和引用,防止内存泄漏

    # 组件之间的循环引用

    假设你需要构建一个文件目录树,像访达或资源管理器那样的。你可能有一个 tree-folder 组件,模板是这样的:

    <p>
      <span>{{ folder.name }}</span>
      <tree-folder-contents :children="folder.children" />
    </p>
    
    1
    2
    3
    4

    还有一个 组件,模板是这样的:

    <ul>
      <li v-for="child in children">
        <tree-folder v-if="child.children" :folder="child" />
        <span v-else>{{ child.name }}</span>
      </li>
    </ul>
    
    1
    2
    3
    4
    5
    6

    当你仔细观察的时候,你会发现这些组件在渲染树中互为对方的后代和祖先——一个悖论!当通过 Vue.component 全局注册组件的时候,这个悖论会被自动解开。如果你是这样做的,那么你可以跳过这里。

    然而,如果你使用一个模块系统依赖/导入组件,例如通过 webpack 或 Browserify,你会遇到一个错误:

    Failed to mount component: template or render function not defined.

    为了解释这里发生了什么,我们先把两个组件称为 A 和 B。模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。

    为了解决这个问题,我们需要给模块系统一个点,在那里 A 反正是需要 B 的,但是我们不需要先解析 B。

    在我们的例子中,把 <tree-folder> 组件设为了那个点。我们知道那个产生悖论的子组件是 <tree-folder-contents> 组件,所以我们会等到生命周期钩子 beforeCreate 时去注册它:

    beforeCreate: function () {
      this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
    }
    
    1
    2
    3

    或者,在本地注册组件的时候,你可以使用 webpack 的异步 import:

    components: {
      TreeFolderContents: () => import('./tree-folder-contents.vue')
    }
    
    1
    2
    3

    这样问题就解决了!

    组件的异步引入解决 组件的循环引用问题

    # 自定义组件的 v-model

    2.2.0+ 新增

    一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:

    Vue.component('base-checkbox', {
      model: { prop: 'checked', event: 'change' }, // 在这里自定义指令的key和触发的事件名
      props: { checked: Boolean },
      template: ``
    })
    
    1
    2
    3
    4
    5
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    />
    
    1
    2
    3
    4
    5

    现在在这个组件上使用 v-model 的时候:

    <base-checkbox v-model="lovingVue"></base-checkbox>
    
    1

    这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。

    注意: 你仍然需要在组件的 props 选项里声明 checked 这个 prop。

    # 自定义指令

    除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。

    注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。

    然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。举个聚焦输入框的例子,如下:

    当页面加载时,该元素将获得焦点 (注意:autofocus 在移动版 Safari 上不工作)。

    事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。

    现在让我们用指令来实现这个功能:

    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('focus', {
      // 当被绑定的元素插入到 DOM 中时……
      inserted: function(el) {
        // 聚焦元素
        el.focus()
      }
    })
    
    1
    2
    3
    4
    5
    6
    7
    8

    上面用到了指令的 inserted 钩子

    如果想注册局部指令,组件中也接受一个 directives 的选项:

    directives: {
      focus: {
        // 指令的定义
        inserted: function (el) {
          el.focus()
        }
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

    然后你可以在模板中任何元素上使用新的 v-focus property,如下:

    <input v-focus>
    
    1

    # 钩子函数

    一个指令定义对象可以提供如下几个钩子函数 (均为可选):

    • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

    • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

    • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

    • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

    • unbind:只调用一次,指令与元素解绑时调用。

    接下来我们来看一下钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。

    指令钩子函数会被传入以下参数:

    • el:指令所绑定的元素,可以用来直接操作 DOM。
    • binding:一个对象,包含以下 property: - name:指令名,不包括 v- 前缀。 - value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。 - oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。 - expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。 - arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。 - modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
      vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
      oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

    这是一个使用了这些 property 的自定义钩子样例:

    <div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
    
    1
    Vue.directive('demo', {
      bind: function(el, binding, vnode) {
        var s = JSON.stringify
        el.innerHTML =
          'name: ' +
          s(binding.name) +
          '<br>' +
          'value: ' +
          s(binding.value) +
          '<br>' +
          'expression: ' +
          s(binding.expression) +
          '<br>' +
          'argument: ' +
          s(binding.arg) +
          '<br>' +
          'modifiers: ' +
          s(binding.modifiers) +
          '<br>' +
          'vnode keys: ' +
          Object.keys(vnode).join(', ')
      }
    })
    
    new Vue({
      el: '#hook-arguments-example',
      data: {
        message: 'hello!'
      }
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    # 插件 (工作中用的少,有点生疏)

    通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成:

    // 调用 `MyPlugin.install(Vue)`
    Vue.use(MyPlugin)
    
    new Vue({
      // ...组件选项
    })
    
    1
    2
    3
    4
    5
    6

    也可以传入一个可选的选项对象:

    Vue.use(MyPlugin, { someOption: true })
    
    1

    Vue.use 会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。

    Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use()。然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use():

    // 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
    var Vue = require('vue')
    var VueRouter = require('vue-router')
    
    // 不要忘了调用此方法
    Vue.use(VueRouter)
    
    1
    2
    3
    4
    5
    6

    # 开发插件

    Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

    MyPlugin.install = function (Vue, options) {
      // 1. 添加全局方法或 property
      Vue.myGlobalMethod = function () {
        // 逻辑...
      }
    
      // 2. 添加全局资源
      Vue.directive('my-directive', {
        bind (el, binding, vnode, oldVnode) {
          // 逻辑...
        }
        ...
      })
    
      // 3. 注入组件选项
      Vue.mixin({
        created: function () {
          // 逻辑...
        }
        ...
      })
    
      // 4. 添加实例方法
      Vue.prototype.$myMethod = function (methodOptions) {
        // 逻辑...
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    # 跟踪运行时错误

    如果在组件渲染时出现运行错误,错误将会被传递至全局 Vue.config.errorHandler 配置函数 (如果已设置)。

    利用这个钩子函数来配合错误跟踪服务是个不错的主意。比如 Sentry,它为 Vue 提供了官方集成。

    目前错误定位用的较少,可以保持关注,有机会就实操实验下

    # 安全: 注入 JavaScript

    我们强烈不鼓励使用 Vue 渲染

    上次更新: 2023/04/05, 09:41:10
    3个提升Vue性能的写法
    moment.js给定时间获取自然月、周的时间轴

    ← 3个提升Vue性能的写法 moment.js给定时间获取自然月、周的时间轴→

    最近更新
    01
    JavaScript-test
    07-20
    02
    二维码的原理
    07-20
    03
    利用ChatGPT优化代码
    07-20
    更多文章>
    Theme by Vdoing | Copyright © 2021-2023 XingYun | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式