vue API 知识点(1)---全局 API 总结

1.Vue.extend(options)

  构造器,创建一个 子类 。参数是一个包含组件选项的对象

  data 选项是特例,需要注意 在 Vue.extend() 中它必须是一个函数,

  <div id="test"></div>
  // 创建构造器
  let MyTest = Vue.extend({
    template: '<p>{{name}} {{age}}</p>',
    data(){
      return {
        name: 'zhangning',
        age: '24'
      }
    }
  })

  创建 MyTest 实例,并挂载到一个元素上

  new MyTest().$mount('#test')

  最终结果如下

  <p>zhangning 24</p>

  上面 extend 创建的是 Vue 构造器,而不是一个具体的组件实例,所以不能够通过 new Vue({components: testExtend}) 来直接使用,需要通过 new MyTest().$mount('#test') 来挂载到指定的元素上

  *调用 Vue.extend() 创建的是一个组件构造器

  *通常在创建组件构造器时,传入 template 代表我们自定义组件的模板

  *该模板就是在使用到组件的地方,要显示的 HTML 代码

  *但是,这种写法在vue2之后几乎就不再使用了,都是直接使用语法糖,不过我们还是要学习的,为后面的学习打下基础

  现在我们通常不使用 Vue.extend() 来注册组件了,使用语法糖的写法,直接把对象放在 Vue.component() 来注册组件,可以看第 7 个API进行学习

    调用Vue.component() 是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名字

    所以需要传递两个参数:1.注册组件的标签名 2.组件构造器

  组件必须挂在在某个Vue实例下,否则不会生效

  示例:封装一个全局提示组件

  首先创建一个 message.vue 组件

  <template>
    <transition>
      <div v-show='show'>{{message}}</div>
    </transition>
  </template>   <script>
    export default{
      data(){
        return {
          show: false,
          message: ''
        }
      }
    }
  </script>   <style scoped>
    div {
      padding: 10px;
      color: #ddd;
      background: red;
      text-align: center;
      position: fixed;
      top: 30%;
      left: 50%;
    }
  </style>

  然后在 main.js 中配置

  import Message from './components/Message.vue'

  const MessageM = {
    install: function(Vue) {
      // 创建一个 vue 的子类组件
      const MessageConstructor = Vue.extend(Message)
      // 创建子类实例,并挂载到动态创建的元素上,并将元素添加到全局结构中
      const inst = new MessageConstructor().$mount(document.createElement('div'))
      document.body.appendChild(inst.$el)
      // 在 vue 原型链上注册方法,控制组件
      Vue.prototype.$message = (msg, time = 1000) => {
        inst.message = msg
        inst.show = true
        setTimeout((
          inst.show = false
        ), time)
      }
    }
  }
  Vue.use(MessageM)

  在组件内使用

  this.$message('消息提示')

  以上就是一个简单的全局消息提示

2.Vue.nextTick

  在写词DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM

<template>
<div>
<div ref='valRef'>{{ val }}</div>
<div>{{ val1 }}</div>
<div>{{ val2 }}</div>
<div>{{ val3 }}</div>
<el-button type="primary" @click.once='handleClick'>改变val</el-button>
</div>
</template> <script>
export default {
name: 'index',
data() {
return {
val: 'zhangning',
val1: '',
val2: '',
val3: ''
}
},
methods: {
// 点击按钮时,val1和val3获取的是初次加载时候的val的值,因为vue的DOM是异步加载,
// 而使用了nextTick的val2的值在msg改变之后,就立刻获取到了val更新之后的值
handleClick() {
this.val = '我已改变';
// DOM 未更新,获取不到最新的dom
this.val1 = this.$refs.valRef.innerHTML;
this.$nextTick(() => {
// DOM 已更新,获取最新的dom
this.val2 = this.$refs.valRef.innerHTML;
})
// DOM 未更新,获取不到最新的dom
this.val3 = this.refs.valRef.innerHTML;
}
}
}
</script>

  官方给出的解释和例子(异步更新队列)

  Vue 在更新 DOM 时是异步执行的。只要监听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更,如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然而在下一个的事件循环 tick 中,Vue 刷新队列并执行实际(已去重)工作。Vue 在内部对异步队列尝试使用原生的Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。

  例如,当设置 vm.someData = 'newVlaue',该组件不会立即重新渲染,当刷新队列时,组件会在下一个事件循环 tick 中更新。多数情况我们不需要关心这个过程,但是如果想基于更新后的 DOM 状态做点什么,这就有点棘手。虽然Vue鼓励我们使用数据驱动的方式思考,避免直接接触 DOM ,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成之后被调用。例如

<div id="example">{{message}}</div>
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})

在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue ,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '未更新'
}
},
methods: {
updateMessage: function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '已更新'
})
}
}
})

  因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的语法 async/await 完成相同的事情

methods: {
updateMessage: async function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}

3.Vue.set

  Vue.set(target, key, value)

    target:要更改的数据源(可以是对象或者数组)

    key:要更改的具体数据

    value:重新赋的值

  由于 js 的限制,Vue 不能检测出数据的改变,但是通过这种方法修改数组中的数据,就会检测到数组的改变,是响应式的

  用法:向响应式对象中添加一个 property, 并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 arr[1] = 110)

export default {
name: 'index',
data() {
return {
arr: [1,2,3]
}
},
methods: {
// 修改 arr[1] 变为 200
handleChange(){
this.$set(this.arr, 1, 200);// arr: [1, 200, 3]
},
// arr 数组添加元素 600
handleAddArr(){
this.$set(this.arr, this.arr.length, 600);
}
}
}

4.Vue.delete()

  Vue.delete(target, key, value)

    target:要删除的数据源(可以是对象或者数组)

    key:要删除的具体数据

  用法:删除对象的 property。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到 property 被删除的限制,虽然很少使用,但直到要会用

export default {
name: 'index',
data() {
return {
zhangning: {
height: 187,
name: 'zhangning',
sex: '男'
}
}
},
methods: {
// 删除 name
handleDeleteName() {
this.$set(this.zhangning, 'name');
}
}
}

5.Vue.directive()

  Vue.directive(string, Function | Object)

  注册或获取全局指令

  声明周期:

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

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

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

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

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

  钩子函数参数

    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 编译生成的虚拟节点

    oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

    <div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
    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!'
      }
    })

    页面展示效果如下

    name: 'demo'
    value: 'hello!'
    expression: 'message'
    argument: 'foo'
    modifiers: {a: true, b: true}
    vnode keys: tag,data,children,text,elm,ns,context...

  动态指令参数,指令的参数可以是动态的,例如,在 v-mydirective:[argument]='value'中,argument 参数可以根据组件数据进行更新,这可以让我们的自定义指令灵活使用。

  创建一个自定义指令,把元素固定在距离顶部 200px 的位置

  <div id="test">
    <p>Scroll down the page</p>
    <p v-pin="200">距离顶部200px</p>
  </div>
  Vue.directive('pin', {
    bind: function(el, binding, vnode){
      el.style.position = 'fixed'
      el.style.top = binding.value + 'px'
    }
  })   new Vue({
    el: '#test'
  })

  当我们需要固定在左侧而不是顶部的时候,这时候我们就需要用到动态指令

  <div id="test">
    <p>Scroll down the page</p>
    <p v-pin:[direction]="200">距离顶部200px</p>
  </div>
  Vue.directive('pin', {
    bind: function(el, binding, vnode){
      el.style.position = 'fixed'
      let s = binding.arg == 'left' ? 'left' : 'top'
      el.style[s] = binding.value + 'px'
    }
  })   new Vue({
    el: '#test' ,
    data(){
      return {
        direction: 'left'
      }
    }
  })

    以上这个自定义指令现在的灵活性就足以支持一些不同的用例了

  函数简写

    很多时候,我们想在 bind 和 update 时触发相同行为,而不关心其他的钩子。

    Vue.directive('pin', function(el, binding){
      el.style.top = binding.value + 'px'
    })

    如果指令需要多个值,可以传入 js 对象,指令函数能够接收所有合法的 js 表达式

    <div v-demo="{ color: 'red', text: 'hello'}"></div>
    Vue.directive('demo', function(el, binding){
      console.log(binding.value.color) // red
      console.log(binding.value.text) // hello
    })

  在项目中使用的案例

    通过权限控制每个页面的按钮,

  先定义一个 directive.js,写上全局指令

import Vue from 'vue';
import store from './store'; Vue.directive('permission', {
inserted: (el, binding) => {
if (store.getters.userButtons.length) {
const buttons = store.getters.userButtons;
if (buttons.indexOf(binding.value) < 0) el.parentNode.removeChild(el);
} else {
store.dispatch('getInfo').then(data => {
const { buttons } = data.buttons;
if (buttons.indexOf(binding.value) < 0) el.parentNode.removeChild(el);
});
}
}
});

  在 main.js 中全局引入

import './directive.js'

  在 vue 组件中使用,判断有没有下载按钮权限

    <el-button
round
icon="el-icon-document"
type="primary"
v-permission="'SJML_SQXZ'"
@click="applyForDownload"
    >下载文档</el-button>

6.Vue.filter()

  定义过滤器,可被用于常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式,过滤器应该被添加在 js 表达式的尾部,由管道符号指示:'|'

  <!-- 在双花括号中 -->
  {{ message | capitalize }}

  <!-- 在 `v-bind` 中 -->
  <div v-bind:id="rawId | formatId"></div>

  在一个组件的选项中定义本地过滤器

  filters: {
    capitalize: function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }

  在创建 Vue 实例之前全局定义过滤器

  Vue.filter('capitalize', function() {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  })
  new Vue({
    // ...
  })

  注意:当全局过滤器和局部过滤器重名时,会采用局部过滤器

  过滤器函数总接收表达式的值作为第一个参数

  过滤器可以串联:

    {{ message | filterA | filterB }}

  这个例子中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递给 filterB 中。

  过滤器时 js 函数,因此可以接收参数

    {{ message | filterA('arg1', arg2) }}

  这个例子,filterA 被定义为接收三个参数的过滤器函数,其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数, arg2 作为第三个参数

  在项目中使用的案例

  先定义一个 filters.js

export { formatBoolean, formatDate, formatNum, formatStatus };

// 布尔值
function formatBoolean(value) {
return value ? "是" : "否";
} // 状态
function formatStatus(value) {
return value ? "成功" : "失败";
}
// 时间戳转换
function formatDate(value) {
let date = new Date(parseInt(value));
let Y = date.getFullYear();
let M =
date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1;
// let D = date.getDate();
let D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
let h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
let m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
let s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return Y + "." + M + "." + D + " " + h + ":" + m + ":" + s;
} // 数值加逗号
function formatNum(num) {
num = (num || 0).toString();
let result = "";
while (num.length > 3) {
result = "," + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return result;
}

  然后在 main.js 中进行全局引入

  import * as filters from './filters.js'
  Object.keys(filters).forEach(item => {
    Vue.filter(item, filters[item])
  })

  // 这里讲一下 Object.keys() 方法,表示给定对象的所有可枚举属性的字符串数组
  let zn = {name: 'zhangning', age: '24', height: '187'}
  Object.keys(zn);// ['name', 'age', 'height'] 返回可枚举属性组成的数组
  // 处理数组,返回索引值数组
  let arr = [100, 200, 300, 400, 500]
  Object.keys(arr);// ['0', '1', '2', '3', '4'] 返回索引值字符串组成的数组
  // 处理字符串,返回索引值数组
  let str = 'zhang';
  Object.keys(str);// ['0', '1', '2', '3', '4']
  // 常用技巧
  let zn = {name: 'zhangning', age: '25', address: '合肥', getName: function()}
  Object.keys(person).map(item => {
    person[item] // 获取到属性对应的值,做一些处理
  })

7.Vue.component()

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

  data 必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝,如果不是一个函数,就会影响到组件所有实例

  在项目中自定义全局组件案例

  首先创建一个组件 download.vue

  然后创建一个 download.js,在 js 中引入组件

  // 引入组件
  import DLFLoading from './index.vue';
  // 自定义组件对象
  const DownloadDialog = {
    // install 是默认的方法。当外界在 use 这个组件的时候,就会调用本身的 install 方法,同时传一个 Vue 这个类的参数
    install: function(Vue) {
      // Vue.component() 与正常的全局注册组件用法相同,可以理解为通过 install 和 Vue.use()函数注册了全局组件
      Vue.component('DownloadDialog', DLFLoading);
    }
  }
  // 导出
  export default DownloadDialog;

  接着在 main.js 中全局引入组件

  // 全局引入自定义下载 loading
  import DownloadDialog from '@/components/DownloadDialog/download.js';
  Vue.use(DownloadDialog);

  最后在项目中直接就可以使用

  <DownloadDialog
@cancelDownload="cancelDownload"
:downloadOver="downloadOver"
:downloadLoading="downloadLoading"
></DownloadDialog>

8.Vue.use()

  安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。

  该方法需要在 new Vue() 之前被调用

  当 install 方法被同一个插件多次调用,插件将只会被安装一次。

  插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制 一般有以下几种

    1.添加全局方法或者property

    2.添加全局资源:指令/过滤器/过渡等

    3.通过全局混入来添加一些组件选项

    4.添加 Vue 实例方法,通过把他们添加到 Vue.prototype 上实现

    5.一个库,提供自己的 api,同时提供上面提到的一个或多个功能

  使用插件

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

    // 调用 MyPlugin.install(Vue)
    Vue.use(MyPlugin)
    new Vue({       // ...组件选项
    })

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

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

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

9.Vue.mixin()

  全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。插件作者可以使用混入,向组件注入自定义的行为(官方不推荐使用)

  官网全局混入案例。混入也可以进行全局注册,使用时格外小心,一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,它可以用来自定义选项注入处理逻辑。

  // 为自定义的选项 myOption 注入一个处理器

  Vue.mixin({
    created: function(){
      var myOption = this.$options.myOption
      if(myOption) {
        console.log(myOption)
      }
    }
  })   new Vue({
    myOption: 'zhangning'
  })
  // => 'zhangning'

  注意:要谨慎使用全局混入,因为它影响每个单独创建的 Vue 实例(包括第三方组件)。大多数情况下,之应当应用于自定义选项,就像上面实例一样,推荐将其作为插件发布,以避免重复应用混入

  使用案例

  定义一个 mixin.js

  let MiXin = {
    data(){
      return {
        name: 'zhangning'
      }
    },
    created(){
      console.log('这是mixin中的name', this.name)
    },
    mounted(){},
    methods: {}
  }
  export default MiXin
  // 全局引入

  import mixin from './mixin'
  Vue.mixin(mixin)   // 在 vue 组件中局部引入
  import '@/mixin'
  export default {
    mixins: [mixin]
  }

  混入和组件的合并注意事项

  1.数据对象 data 在内部进行递归合并,在和组件的数据发生冲突时以组件数据优先

  2.同名钩子函数(created,mounted)将混合为一个数组,都将被调用。另外混入对象的钩子将在组件自身钩子之前调用

  3.值为对象的选项(methods,components,directives)将被混合为同一个对象,两个对象键名冲突时,去组件对象的键值对

10.Vue.compile() -- 模板渲染

  将一个模板字符串编译成 render 函数。旨在完整版时可用

  let res = Vue.compile('<div><span>{{ massage }}</span></div>')

  new Vue({

    data: {

      message: 'hello'

    },

    render: res.render,

    staticRenderFns: res.staticRenderFns

  })

  以上是官网给的一个小实例。

  以后深入理解之后,再回来更新

11.Vue.observable() -- 可用于组件间共享数据

  让一个对象可响应,Vue 内部会用它来处理 data 函数返回的对象。

  返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时出发相应的更新。

  处理简单的跨组件共享数据状态的问题,可以说是个精简的 vuex

  示例

  创建store.js

  import Vue from 'vue'
  export const store = Vue.observable({num: 0})
  export const mutations = {
    setNum (num) {
      store.num = num
    }
  }

  在组件中使用(所有的说明都没有举例子来的实在,理解的更快)

  <template>
    <div>
      <span>选择数量</span>
      <button @click="setNum(num + 1)"> + </button>
      <span>count</span>
      <button @click="setNum(num - 1)"> - </button>
    </div>
  </template>   <script>
    import { store, mutations } from '@/store/store'
    export default {
      name: 'numIndex',
      computed: {
        count() {
          return store.num
        }
      },
      methods: {
        setNum: mutations.setNum
      }
    }
  </script>

12.Vue.version()

  提供字符串形式的 Vue 安装版本号。这对社区的插件和组件来说非常有用,你可以根据不同的版本号采取不同的策略

  let version = Number(Vue.version.split('.')[0])

  if (version == 2) {

  } else if (version == 1) {

  } else {}

  就是获取当前使用的 vue 版本号,原理就是读取 package.json 中的 version 字段

  以上就是 vue API 全局 API 的所有内容,

  宝剑锋从磨砺出,梅花香自苦寒来。

上一篇:vue API 知识点(3) --- 实例 总结


下一篇:内置函数dict