Vue extend $mount 构造器详解

2020-04-01 10:21:20

参考地址 Vue 的构造器——extend 与手动挂载——$mount

本节介绍两个 Vue.js 内置但却不常用的 API——extend 和 $mount,它们经常一起使用。不常用,是因为在业务开发中,基本没有它们的用武之地,但在独立组件开发时,在一些特定的场景它们是至关重要的。


使用场景

我们在写 Vue.js 时,不论是用 CDN 的方式还是在 Webpack 里用 npm 引入的 Vue.js,都会有一个根节点,并且创建一个根实例,比如:


<body>

  <div id="app"></div>

</body>

<script>

  const app = new Vue({

    el: '#app'

  });

</script>


Webpack 也类似,一般在入口文件 main.js 里,最后会创建一个实例:


import Vue from 'vue';

import App from './app.vue';


new Vue({

  el: '#app',

  render: h => h(App)

});


因为用 Webpack 基本都是前端路由的,它的 html 里一般都只有一个根节点 <div id="app"></div>,其余都是通过 JavaScript 完成,也就是许多的 Vue.js 组件(每个页面也是一个组件)。


有了初始化的实例,之后所有的页面,都由 vue-router 帮我们管理,组件也都是用 import 导入后局部注册(也有在 main.js 全局注册的),不管哪种方式,组件(或页面)的创建过程我们是无需关心的,只是写好 .vue 文件并导入即可。这样的组件使用方式,有几个特点:


所有的内容,都是在 #app 节点内渲染的;

组件的模板,是事先定义好的;

由于组件的特性,注册的组件只能在当前位置渲染。

比如你要使用一个组件 <i-date-picker>,渲染时,这个自定义标签就会被替换为组件的内容,而且在哪写的自定义标签,就在哪里被替换。换句话说,常规的组件使用方式,只能在规定的地方渲染组件,这在一些特殊场景下就比较局限了,例如:


组件的模板是通过调用接口从服务端获取的,需要动态渲染组件;

实现类似原生 window.alert() 的提示框组件,它的位置是在 <body> 下,而非 <div id="app">,并且不会通过常规的组件自定义标签的形式使用,而是像 JS 调用函数一样使用。

一般来说,在我们访问页面时,组件就已经渲染就位了,对于场景 1,组件的渲染是异步的,甚至预先不知道模板是什么。对于场景 2,其实并不陌生,在 jQuery 时代,通过操作 DOM,很容易就能实现,你可以沿用这种思路,只是这种做法不那么 Vue,既然使用 Vue.js 了,就应该用 Vue 的思路来解决问题。对于这两种场景,Vue.extend 和 vm.$mount 语法就派上用场了。


用法

上文我们说到,创建一个 Vue 实例时,都会有一个选项 el,来指定实例的根节点,如果不写 el 选项,那组件就处于未挂载状态。Vue.extend 的作用,就是基于 Vue 构造器,创建一个“子类”,它的参数跟 new Vue 的基本一样,但 data 要跟组件一样,是个函数,再配合 $mount ,就可以让组件渲染,并且挂载到任意指定的节点上,比如 body。


比如上文的场景,就可以这样写:


import Vue from 'vue';


const AlertComponent = Vue.extend({

  template: '<div>{{ message }}</div>',

  data () {

    return {

      message: 'Hello, Aresn'

    };

  },

});


这一步,我们创建了一个构造器,这个过程就可以解决异步获取 template 模板的问题,下面要手动渲染组件,并把它挂载到 body 下:


const component = new AlertComponent().$mount();

1

这一步,我们调用了 $mount 方法对组件进行了手动渲染,但它仅仅是被渲染好了,并没有挂载到节点上,也就显示不了组件。此时的 component 已经是一个标准的 Vue 组件实例,因此它的 $el 属性也可以被访问:


document.body.appendChild(component.$el);

1

当然,除了 body,你还可以挂载到其它节点上。


$mount 也有一些快捷的挂载方式,以下两种都是可以的:


// 在 $mount 里写参数来指定挂载的节点

new AlertComponent().$mount('#app');

// 不用 $mount,直接在创建实例时指定 el 选项

new AlertComponent({ el: '#app' });


实现同样的效果,除了用 extend 外,也可以直接创建 Vue 实例,并且用一个 Render 函数来渲染一个 .vue 文件:


import Vue from 'vue';

import Notification from './notification.vue';


const props = {};  // 这里可以传入一些组件的 props 选项


const Instance = new Vue({

  render (h) {

    return h(Notification, {

      props: props

    });

  }

});


const component = Instance.$mount();

document.body.appendChild(component.$el);



这样既可以使用 .vue 来写复杂的组件(毕竟在 template 里堆字符串很痛苦),还可以根据需要传入适当的 props。渲染后,如果想操作 Render 的 Notification 实例,也是很简单的:


const notification = Instance.$children[0];

1

因为 Instance 下只 Render 了 Notification 一个子组件,所以可以用 $children[0] 访问到。


如果你还不理解这样做的目的,没有关系,后面小节的两个实战你会感受到它的用武之地。


需要注意的是,我们是用 $mount 手动渲染的组件,如果要销毁,也要用 $destroy 来手动销毁实例,必要时,也可以用 removeChild 把节点从 DOM 中移除。


结语

这两个 API 并不难理解,只是不常使用罢了,因为多数情况下,我们只关注在业务层,并使用现成的组件库。


使用 Vue.js 也有二八原则,即 80% 的人看过 Vue.js 文档教程篇,20% 的人看过 Vue.js 文档 API。



  • 2020-11-17 11:57:55

    app抓不到包,解决很简单

    1.手机安装virtualXpost 并激活xpost 框架,如有问题自行百度。 2.安装justTrustMe,然后再virtualXpost中添加此模块 3.安装手机抓包神器packet capture 4.在virtualXpost中运行app,并打开packet capture抓包就行

  • 2020-11-17 16:50:16

    JS常见加密混淆方式

    目录 前端js常见混淆加密保护方式 eval方法等字符串参数 emscripten WebAssembly js混淆实现 JSFuck AAEncode JJEncode 代码压缩 变量名混淆 字符串混淆 自我保护,比如卡死浏览器 控制流平坦化 僵尸代码注入 对象键名替换 禁用控制台输出 调试保护,比如无限Debug,定时Debug 域名锁定

  • 2020-11-17 17:08:28

    用js编写WebAssembly ,WebAssembly 现状与实战

    自从 JavaScript 诞生起到现在已经变成最流行的编程语言,这背后正是 Web 的发展所推动的。Web 应用变得更多更复杂,但这也渐渐暴露出了 JavaScript 的问题:

  • 2020-11-17 17:28:06

    AssemblyScript 开发WebAssembly 教程

    WebAssembly 以及通过 AssemblyScript 的扩展,不会使每个网站都神奇地变得更快,但是这并不重要。 WebAssembly 之所以令人兴奋,是因为它可以使更多的应用在 Web 变得中可行。

  • 2020-11-17 21:15:48

    如何保障 API 接口的安全性?前端如何加密

    一、1. HTTP 请求中的来源识别 二、2. 数据加密 三、3. 数据签名 四、4. 时间戳 五、5. AppID 六、6. 参数整体加密 七、7. 限流 八、8. 黑名单 九、1. 压缩 十、2. 混淆 undefined、3. 加密

  • 2020-11-18 14:34:00

    当你写爬虫抓不到APP请求包的时候该怎么办?

    提示:因为高级篇以后的APP将无法使用很通用的方式处理,每种类型甚至是每个APP的反抓包处理方式都会有差别,所以这个系列以后会以【高级篇-具体类型】的形式来写。

  • 2020-11-21 20:41:51

    Kotlin Sealed class类详解

    Sealed class(密封类) 是一个有特定数量子类的类,看上去和枚举有点类似,所不同的是,在枚举中,我们每个类型只有一个对象(实例);而在密封类中,同一个类可以拥有几个对象。

  • 2020-11-22 20:53:43

    Dagger2之Kotlin写法

    修饰构造方法 修饰变量,在宿主类里,引入要注入的实例