文章目录

  • 『 总览 』
  • 『 Vue.extend 』
  • 『 Vueponent 』
  • 『 Vue.nextTick 』
  • 『 Vue.set 』
  • 『 Vue.delete 』
  • 『 Vue.directive 』
  • 『 Vue.filter 』
  • 『 Vue.use 』
  • 『 Vue.mixin 』
  • 『 Vuepile』
  • 『 Vue.version 』

『 总览 』

Vue.extend(options)                 // 返回一个子类构造函数,也就是预设部分选项的vue实例构造器
Vue.component(id, [definition])     // 注册或获取全局组件
Vue.nextTick([callback, context])   // 在下次 DOM 更新循环结束之后执行延迟回调
Vue.set(target, key, value)         // 设置对象的属性,如果是响应式对象,将会触发视图更新
Vue.delete(target, key)             // 删除对象的属性,如果是响应式对象,将会触发视图更新
Vue.directive(id, [definition])     // 注册或获取全局指令
Vue.filter(id, [definition])        // 注册或获取全局过滤器
Vue.use(plugin)                     // 安装 Vue 插件
Vue.mixin(mixin)                    // 全局注册一个 mixin 对象
Vue.compile(template)               // 在 render 函数中编译模板字符串
Vue.version                         // 提供当前使用 Vue 的版本号

『 Vue.extend 』

实际业务开发中我们很少使用,因为它返回的是组件构造函数,而不是我们平时常写的组件实例,所以不可以通过 new Vue({ components: 组件名 }) 来直接使用,比常用的 Vueponent 写法要更加繁琐一些,对比 Vueponent,更适用于不需要使用组件名称来进行注册和使用的组件
使用场景:独立组件开发(Vue.extend + $mount),例如实现通知弹窗组件

// 使用
this.$notice(Notice, {
 title: '通知弹窗组件',
 message: '提示信息',
 duration: 1000
}).show();
// create 方法
import Vue from "vue";
// 创建它的实例,并且将他挂载到 body 上
// 返回组件实例
function create(Component, props) {
  // 1. Vue.extend(options) 方式
  const Ctor = Vue.extend(Component);
  const comp = new Ctor({propsData: props}); // 创建组件实例
  comp.$mount(); // 不指定宿主元素,则会创建真实 DOM,但是不会追加操作
  document.body.appendChild(comp.$el); // 将真实 DOM 挂载到 body 上
  comp.remove = () => {
    document.body.removeChild(comp.$el); // 移除 DOM
    comp.$destroy(); // 销毁组件
  };
  
  // 2. render 方式
 	// const vm = new Vue({
  //    render(h) {
  //      // h 是 createElement,返回 VNode,是虚拟 DOM
  //      // 需要挂载才能变成真是 DOM
  //      return h(Component, { props });
  //    }
  //  }).$mount(); // 本质上将vdom => dom,不指定宿主元素,则会创建真实 DOM,但是不会追加操作。如果指定宿主元素,则会直接覆盖

  //  document.body.appendChild(vm.$el); // 获取真实 DOM
  //  const comp = vm.$children[0]; // 给组件实例添加销毁⽅法

  //  comp.remove = () => { // 删除
  //    document.body.removeChild(vm.$el);
  //    vm.$destroy();
  //  };
  return comp;
}
// 暴露调⽤接⼝
export default create;
// Notice.vue 通知组件
<template>
 <div class="box" v-if="isShow">
   <h3>{{title}}</h3>
   <p class="box-content">{{message}}</p>
 </div>
</template>

<script>
export default {
 props: {
   title: {
     type: String,
     default: ""
   },
   message: {
     type: String,
     default: ""
   },
   duration: {
     type: Number,
     default: 1000
   }
 },
 data() {
   return {
   	isShow: false
   };
 },
 methods: {
   show() {
     this.isShow = true;
     setTimeout(this.hide, this.duration);
   },
   hide() {
     this.isShow = false;
     this.remove();
   }
 }
};
</script>
<style>
.box {
 position: fixed;
 width: 100%;
 top: 16px;
 left: 0;
 text-align: center;
 pointer-events: none;
 background-color: #fff;
 border: grey 3px solid;
 box-sizing: border-box;
}
.box-content {
 width: 200px;
 margin: 10px auto;
 font-size: 14px; 
 padding: 8px 16px;
 background: #fff;
 border-radius: 3px;
 margin-bottom: 8px;
}
</style>
// 使⽤插件进⼀步封装便于使⽤,create.js
import Notice from '@/components/Notice.vue'
//...
export default {
 install(Vue) {
   Vue.prototype.$notice = function (options) {
   	 return create(Notice, options)
   }
 }
}

『 Vueponent 』

全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生,内部实质上调用了 Vue.extend

<div id="app">        
    <div>#app</div>        
    <my-header></my-header>        
    <my-main></my-main>        
    <my-footer></my-footer>    
</div>    
<div id="root">        
    <div>#root</div>        
    <my-header></my-header>        
    <my-main></my-main>        
    <my-footer></my-footer>    
</div>

<script type="text/javascript" src="./vue.js"</script>
<script>    
    // 定义组件    
    const Header = {        
        template: '<header>全局头部组件</header>'    
    };    
    const Main = {
        template: '<main>局部主体组件</main>'    
    };   
    const Footer = {       
        template: '<footer>全局尾部组件</footer>'    
    };
    
    // 全局注册组件
    // Vueponent('组件名'[, 组件的配置对象])
    Vue.component('my-header', Header);
    Vue.component('my-footer', Footer);
    
    // 第一个实例    
    new Vue({        
        el: '#app',        
        // 局部注册组件——内容        
        components: {            
            'my-main': Main        
        }    
     });  
    // 第二个实例    
    new Vue({        
        el: '#root',    
    })
</script>

页面运行结果

#app
全局头部组件
局部主体组件
全局尾部组件
#root
全局头部组件
全局尾部组件

控制台运行结果

[Vue warn]: Unknown custom element: <my-main> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

(found in <Root>)

会报错:没有注册局部主体组件


『 Vue.nextTick 』

下面了解下 nextTick 的主要应用的场景及原因

  • 在Vue生命周期的 created() 钩子函数进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中

  • created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick() 的回调函数中

  • 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的 DOM 结构的时候,这个操作都应该放进 Vue.nextTick() 的回调函数中

<div class="app">
  <div ref="msgDiv">{{msg}}</div>
  <div v-if="msg1">Message got outside $nextTick: {{msg1}}</div>
  <div v-if="msg2">Message got inside $nextTick: {{msg2}}</div>
  <div v-if="msg3">Message got outside $nextTick: {{msg3}}</div>
  <button @click="changeMsg">
    Change the Message
  </button>
</div>
new Vue({
  el: '.app',
  data: {
    msg: 'Hello Vue.',
    msg1: '',
    msg2: '',
    msg3: ''
  },
  methods: {
    changeMsg() {
      this.msg = "Hello world."
      this.msg1 = this.$refs.msgDiv.innerHTML
      /**
       * Vue.nextTick(options)
       * 用于延迟执行一段代码
       * 接受2个参数(回调函数和执行回调函数的上下文环境)
       * 如果没有提供回调函数,那么将返回 promise 对象
       */
      this.$nextTick(() => {
        this.msg2 = this.$refs.msgDiv.innerHTML
      })
      this.msg3 = this.$refs.msgDiv.innerHTML
    }
  }
})

『 Vue.set 』

Vue.set(target, key, value)

  • target: 要更改的数据源(可以是对象或者数组)
  • key: 要修改的变量
  • value: 重新赋的值

如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。当你把一个普通的 js 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter
受现代 js 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
Vue 不允许在已经创建的实例上动态添加新的根级响应式属性 (root-level reactive property)。然而它可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上。


『 Vue.delete 』

Vue.delete(target, key)

  • target: 要更改的数据源(可以是对象或者数组)
  • key: 要删除的变量

删除对象的属性,如果对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限制


『 Vue.directive 』

Vue 允许注册自定义指令,用于对底层 DOM 进行操作

// Vue.directive(id[, definition])
Vue.directive("focus", {
  /**
   * 下列钩子函数拥有如下参数
   * el -> 指令绑定的 HTML 元素,可以用来直接操作 DOM
   * vnode -> Vue编译生成的虚拟节点
   * oldVnode -> 之前的虚拟节点,仅在 update、componentUpdated 钩子中可用
   * binding -> 一个对象,包含以下属性:
   * * name -> 指令名称,不包括 v- 前缀
   * * value -> 指令的绑定值,例如 v-my-directive="1 + 1" 中 value 的值是2
   * * oldValue -> 指令绑定的之前一个值,仅在 update、componentUpdated 钩子中可用
   * * expression -> 绑定值的字符串形式,例如 v-my-directive="1 + 1" 当中 expression 的值为"1 + 1"
   * * arg -> 传给指令的参数,例如 v-my-directive:foo中arg 的值是 "foo"
   * * modifiers -> 包含修饰符的对象,例如 v-my-directive.foo.bar 的 modifiers 的值是 {foo: true, bar: true}
   */
  bind() {
    // 指令第一次绑定到元素时调用,只会调用一次,可以用来执行一些初始化操作。
  },
  inserted(el) {
    // 被绑定元素插入父节点时调用。
  },
  update() {
    // 所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。
  },
  componentUpdated() {
    // 所在组件VNode及其子VNode全部更新时调用。
  },
  unbind() {
    // 指令与元素解绑时调用,只会被调用一次。
  }
})
// btnPermisstion.js
import store from '@/store/index'

export default {
  install (Vue) {
    Vue.directive('has', {
      bind (el, binding) {
        const permissionCode = binding.value
        const permissionList = store.getters.btnPermissions
        if (permissionList.indexOf(permissionCode) === -1) {
          Vue.prototype.$nextTick(() => {
            el.parentNode.removeChild(el)
          })
        }
      }
    })
  }
}

// main.js
import btnsPermission from './directive/btnPermisstion'
......

Vue.use(btnsPermission)

『 Vue.filter 』

Vue 可以通过定义过滤器,进行一些常见的文本格式化,可以用于 mustache 插值和 v-bind 表达式当中,使用时通过管道符 | 添加在表达式尾部,和计算属性的区别在于不用依赖 data 当中的属性

// filters.js
const numUnitConversion = value => {
  return value >= 10000 ? (value / 10000).toFixed(1) : value
}

const stubValue = value => {
  if (!value) {
    return '-'
  } else {
    return value
  }
}

export {
  stubValue,
  numUnitConversion
}
// main.js
import * as filters from './common/filters'

// 全局过滤器设置
Object.keys(filters).forEach(key => {
  // Vue.filter(id[, definition])
  Vue.filter(key, filters[key])
})

直接用过滤管道符 | 连接需要过滤的数据和定义配置的过滤函数即可

<div class="info_tit info_last">
  <span>磁盘总量</span>
	<span><i class="color_6">{{ rectangleData.diskNum | stubValue }}</i> TB</span>
</div>

『 Vue.use 』

Vue 通过插件来拓展一些全局功能,Vue 插件都会覆写其 install() 方法,该方法第1个参数是 Vue 构造器, 第2个参数是可选的 option 对象
Vue 首先判断这个插件是否被注册过,不允许重复注册
如果我们传入一个包含 install 方法的对象,那么我们就调用这个 install 方法并将整理好的数组当成参数传入 install 方法中
如果我们传入一个函数,那么我们就直接调用这个函数并将整理好的数组当成参数传入
之后给这个插件添加至已经添加过的插件数组中,表示已经注册过,最后返回 Vue 对象

MyPlugin.install = function (Vue, options) {
  // 添加全局方法或属性
  Vue.myGlobalMethod = function () {}
  // 添加全局资源
  Vue.directive("my-directive", {
    bind (el, binding, vnode, oldVnode) {}
  })
  // 注入组件
  Vue.mixin({
    created: function () {}
  })
  // 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {}
}
// Vue.use(plugin[, options])
Vue.use(MyPlugin, {someOption: true})

vue-router 等插件检测到 Vue 是全局对象时会自动调用 Vue.use() ,如果在 CommonJS 模块环境中,则需要显式调用 Vue.use()


『 Vue.mixin 』

使用全局 mixins 将会影响到所有之后创建的 Vue 实例,如果我们并不想给每一个组件实例都混入这些配置 options,而只是个别的组件,最好不要使用 mixin,它可能会影响到我们组件的性能。

// *.vue
<template>
  <div id="box">
    <nav-header ref="navHeader" title="AI-fisher" :styleObject="navHeaderStyle" :shareParams="shareParams"></nav-header>
    ......
    <cube-scroll :options="options" :listenScroll="true" @scroll="scrolling" ref="scroll">
      ......
    </cube-scroll>
		......
  </div>
</template>
// main.js
Vue.mixin({
  data () {
    return {
      navHeaderStyle: {
        opacity: 0
      }
    }
  },
  methods: {
    scrolling(a) {
      let num = ~Math.floor(a.y) > 0 ? ~Math.floor(a.y) > 128 ? 128 : ~Math.floor(a.y) : 0
      this.navHeaderStyle.opacity = num / 128
    }
  }
})

『 Vuepile』

render 函数中编译模板字符串。只在独立构建时有效

// Vuepile(template)
const res = Vue.compile('<div><span>{{ msg }}</span></div>')
 
new Vue({
  data: {
    msg: 'hello'
  },
  render: res.render,
  staticRenderFns: res.staticRenderFns
})

『 Vue.version 』

获取当前使用的 Vue 版本号,在我们去寻找安装的一些依赖包的时候,需要知道支持的 Vue 版本是什么,所以这个时候就会用到这个方法,其原理就是读取 package.json 中的 version 字段

更多推荐

使用 Vue 实例( 全局 API )