1. 引包方式
vue2的引包及入门使用方式可以参考官网安装 — Vue.js (vuejs.org),这里也做一下简单的总结;
1.1 普通引包(直接用 script标签 引入)
- 直接下载并用 script标签引入,Vue会被注册为一个全局变量;
- 在开发环境下不要使用压缩版本,不然你就失去了所有常见错误相关的警告;
- 用来开发选择适合自己项目的版本吗或者官网推荐的稳定版本引入;
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
- 也可以将其下载下来放在本地项目目录中,然后引用;
// vue.min.js就是自己保存的vue包的文件名
<script src="./vue.min.js"></script>
1.2 使用原生ES Modules
<script type="module">
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.esm.browser.js'
</script>
1.3 单文件+webpack模块打包器
- 单文件(.vue)编写 + webpack(vue-template-compiler)编译器;
- 单文件的方式 vue运行时 , 非运行时(写代码时): webpack 使用编译器转化.vue文件;
下面补充几个官网提供的术语
- 完整版:同时包含编译器和运行时的版本;
- 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码;
- 运行时:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切;
2. 手写微型Vue(体现new Vue()时到底做了什么)
- new Vue()时,传递两个必须的参数:dom元素(或者字符串,定位要更新的部分)、数据(要将什么数据更新上去);
new Vue({
el: 'div.box',// 字符串或dom元素(据说 直接传递DOM元素效率更高)
data() { // 这里data传递函数与传递对象相比,可以保证数据更新时不会影响其他元素数据
return {
text: 'hello world'
}
}
});
- 定义一个我们自己的Vue类,接收传进来的参数,这里注意
$$: 内部元素,不支持外部访问;- $ :是外部可以使用的元素;
class Vue {
constructor(option) {
// $$内部不被外部访问 $是外部可以使用的
// 拿到dom元素并保存
this.$$el = this.$el = option.el instanceof HTMLElement ?
option.el : document.querySelector(option.el);
// 拿到data数据并保存
this.$options = {
data: option.data
};
this.$$data = this.$data = this.$options.data();
}
- dom元素所有子元素并遍历拿出所有子节点,这里注意
- dom元素有时会含有空字符文本节点,定义
EMPTY_TEXT = "\n "静态变量来识别并排除此类节点;
class Vue {
constructor(option) {
// $$内部不被外部访问 $是外部可以使用的
// 拿到dom元素并保存
this.$$el = this.$el = option.el instanceof HTMLElement ?
option.el : document.querySelector(option.el);
// 拿到data数据并保存
this.$options = {
data: option.data
};
this.$$data = this.$data = this.$options.data();
// 获取所有子节点
this.elements = this.$$el.childNodes;
// 遍历所有子元素
this.elements.forEach(ele => {}
}
- 判断节点是否为文本节点,或者是否为空文本节点,如果是文本节点就更新文本节点显示的文字内容;
class Vue {
constructor(option) {
// $$内部不被外部访问 $是外部可以使用的
// 拿到dom元素并保存
this.$$el = this.$el = option.el instanceof HTMLElement ?
option.el : document.querySelector(option.el);
// 拿到data数据并保存
this.$options = {
data: option.data
};
this.$$data = this.$data = this.$options.data();
// 获取所有子节点
this.elements = this.$$el.childNodes;
// 遍历所有子元素
this.elements.forEach(ele => {
let isTextNode = ele.nodeType === Node.TEXT_NODE;
if (isTextNode && ele.nodeValue === Vue.EMPTY_TEXT) return; // 排除空的文本节点
// 如果是文本节点
if (isTextNode) {
let textRegex = /\{\{(.*)\}\}/;
let res = textRegex.exec(ele.nodeValue);
if (!res) return;
let key = res[1].trim();
ele.nodeValue = ele.nodeValue.replace(res[0], this.$$data[key])
}
}
}
- 如果不是文本节点,是组件或者元素,控制组件显示的值为输入的值
class Vue {
constructor(option) {
// $$内部不被外部访问 $是外部可以使用的
// 拿到dom元素并保存
this.$$el = this.$el = option.el instanceof HTMLElement ?
option.el : document.querySelector(option.el);
// 拿到data数据并保存
this.$options = {
data: option.data
};
this.$$data = this.$data = this.$options.data();
// 获取所有子节点
this.elements = this.$$el.childNodes;
// 遍历所有子元素
this.elements.forEach(ele => {
let isTextNode = ele.nodeType === Node.TEXT_NODE;
if (isTextNode && ele.nodeValue === Vue.EMPTY_TEXT) return; // 排除空的文本节点
// 如果是文本节点
if (isTextNode) {
let textRegex = /\{\{(.*)\}\}/;
let res = textRegex.exec(ele.nodeValue);
if (!res) return;
let key = res[1].trim();
ele.nodeValue = ele.nodeValue.replace(res[0], this.$$data[key])
}
// 如果不是文本节点
else if (ele.nodeType === Node.ELEMENT_NODE) {
if (ele.tagName === 'INPUT') {
let vModelValeue = ele.getAttribute('v-model');
// value
ele.value = this.$$data[vModelValeue];
// 输入事件
ele.oninput = e => {
// 为了简化功能而写死...
this.elements[0].nodeValue = e.target.value;
}
}
}
});
}
- 附上页面测试元素代码
<div class="box">
{{ text }}
<input type="text" v-model="text" />
</div>
3. 启动方式
- 有template优先template替换el,没有就沿用el内的元素;
- 有el就立刻渲染, 没有就$mount(el) 渲染;
3.1 内含html
- 没有template就沿用el内的元素
<div class="box"> {{ text }} </div>
<script>
new Vue({
el: 'div.box',
data() {
return {
text: 'hello world'
}
}
});
</script>
3.2 传递template
- 有template替换当前的el
<div class="box"> {{ text }} </div>
<script>
new Vue({
el: 'div.box',
template:`
<button> {{ text }} </button>
`,
data() {
return {
text: 'hello world'
}
}
});
</script>
3.3 后续再启动装载
- 有el就立刻渲染, 没有就$mount(el) 渲染;
<script>
let vm = new Vue({
template:`
<button> {{ text }} </button>
`,
data() {
return {
text: 'hello world'
}
}
}).$mount('div.box');
</script>