一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
Vue全家桶的系统学习,其中包括Vue源码分析、Vue-Router的使用和原理、Vuex的用法和原理、Vue-ssr 和 一些常见的Vue面试题。
参考官网 vue.js官网
Vue全家桶的使用,已经是一个老生常谈的话题了。
具体的使用可以去参考Vue的官网,上面有很详细的用法介绍。
从这篇文章开始,我会详细介绍一下Vue全家桶的使用及其原理。
准备工作
我们先要进行前期的准备工作。
首先我们要先创建一个默认的 package.json
文件。
npm init -y
配置文件创建好后,我们就需要使用 rollup 来进行代码编译了。
Rollup环境配置
因为 webpack 太大了,不方便做测试,所以我们会使用 rollup 作为打包工具。
rollup 简单的来说,就是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码。rollup.js 更专注于Javascript类库打包 (开发应用时使用 Webpack,开发库时使用 Rollup)。
随后我们来安装 rollup
及其相应的插件。
npm install @babel/preset-env @babel/core rollup rollup-plugin-babel rollup-plugin-serve cross-env -d
- rollup:我们需要用到的模块打包工具。
- rollup-plugin-babel:babel 与
rollup
之间互通的插件,用来对ES6代码进行转义与编译。 - @babel/preset-env / @babel/core:babel 需要用到的关联插件。
- rollup-plugin-serve:可以用来启动本地服务。
- cross-env:运行跨平台设置和使用环境变量的脚本。
随后我们来创建一个 rollup.config.js
文件作为它的配置文件。
import babel from "rollup-plugin-babel";
import serve from "rollup-plugin-serve";
export default {
input: "./src/index.js",
output: {
format: "umd", // 模块化类型
file: "dist/umd/vue.js",
name: "Vue", // 打包后的全局变量的名字
sourcemap: true,
},
plugins: [
babel({
exclude: "node_modules/**",
}),
process.env.ENV === "development"
? serve({
open: true,
openPage: "/public/index.html",
port: 3000,
contentBase: "",
})
: null,
],
};
配置 .babelrc
文件用来处理babel。
{
"presets": ["@babel/preset-env"]
}
在 package.json
中进行如下配置。
"scripts": {
"build:dev": "rollup -c",
"serve": "cross-env ENV=development rollup -c -w"
}
最终项目结构如下。
|-- vue-test
|-- .babelrc
|-- package-lock.json
|-- package.json
|-- rollup.congfig.js
|-- public
| |-- index.html
|-- src
|-- index.js
这样我们的配置文件就创建完毕了。
初始化流程
使用过Vue后都知道,Vue在作为插件库使用的时候,都是以 option Api (选项进行配置)的形式进行创建的。
var vm = new Vue({
el: '#app',
data() {
return {
a: 1
}
}
})
所以我们第一步要实现的,就是将 Vue作为构造函数,并导出。
导出构造函数
先来看一下完整的导出代码。
import {initMixin} from './init';
function Vue(options) {
this._init(options);
}
initMixin(Vue); // 给原型上新增_init方法
export default Vue;
(注:这里我们不采用ES6类的写法,因为它会将类或函数作为一个整体进行编写。我们希望它可以分散到不同的文件中,所以采用ES5构造函数的方式进行定义,这样在结构上看起来会更清晰。)
-
将创建的构造函数导出,他会接收一个参数options。
options
其实就是我们传入的属性,包括el
、data
、method
等。function Vue(options) { console.log(options); // 实例化时传入的"属性" } export default Vue;
-
新增 _init方法。
options
接收到了,我们就需要通过传入的参数对 Vue进行初始化。function Vue(options) { this._init(options); } Vue.prototype._init = function(){ // ... } export default Vue;
我们再对其进行 解耦,可以得到一个入口方法,可以使所有文件进行初始化操作。
import {initMixin} from './init'; function Vue(options) { this._init(options); } initMixin(Vue); // 给原型上新增_init方法 export default Vue;
这个文件的最终目的是向 Vue原型上扩展方法。
很明显,我们目前就需要对 Vue进行初始化。
初始化Vue状态
上一步中,我们创建了 Vue类,并传入了 options参数。
这一步我们就要将需要的内容封装成插件。
import {initState} from './state';
export function initMixin(Vue){
Vue.prototype._init = function (options) {
const vm = this; // 获取当前实例
vm.$options = options
// 初始化状态
initState(vm);
}
}
options
参数被传入了 vm.$options
中,这样我们就可以使用 $options
来进行配置。
initState
就是对状态进行初始化,也就是对数据进行一个初始化的劫持 (当我改变数据时,视图也会更新)。
根据属性进行初始化操作
**Vue并不完全属于MVVM,它只是参考的MVVM。**其包含的 $ref
就可以说明这个问题,它还是可以操作DOM的。
现在我们就需要对不同的属性进行不同的数据劫持。
export function initState(vm){
const opts = vm.$options;
if(opts.props){
initProps(vm);
}
if(opts.methods){
initMethod(vm);
}
if(opts.data){
// 初始化data
initData(vm);
}
if(opts.computed){
initComputed(vm);
}
if(opts.watch){
initWatch(vm);
}
}
function initProps(){}
function initMethod(){}
function initData(){}
function initComputed(){}
function initWatch(){}
根据不同的传入参数,来进行不同的处理。
下面我们就可以对拆分出来的不同属性,进行不同的初始化处理了。
本篇文章由 莫小尚 创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。 您也可以关注我的 个人站点、博客园 和 掘金,我会在文章产出后同步上传到这些平台上。 最后感谢您的支持!