# Vue2.x 的组件
前言
操作 dom 的不同方式:
方式 步骤一 步骤二 步骤三 步骤四 步骤五 javascript element dom - - - javascript(优化) 文档碎片 element dom - - react render fiber element dom - vue template render Vnode element dom 在 Vue 项目中,组件转为 dom 的大致流程为:template --> render --> Vnode --> element
据此分别在其不同阶段介绍不同方式挂载组件到页面中
# 1.template
- template 中的代码会转化为 render 函数
- 如果是在 vue/cli 工程中,一般会通过 vue-loader 转化为 render 函数
- 如果是在运行时项目中,是通过 complie 函数编译转换成 render 函数
# 1.1 同步组件
# 1.1.1 sfc
最常见的组件
刷新
全屏/自适应
# 1.1.2 运行时
- 内部靠编译函数编译,vue 打包代码会比 cli 的大一些
- 一些特殊项目中使用 vue(如:abi、老项目、动态编辑组件)
<body>
<div id="app"></div>
</body>
<script>
const t1 = `
<div>
<p>{this.msg}</p>
</div>
`
const t2 = `
<div style="color:red">
<container />
</div>
`
new Vue({
el: "#app",
components: {
container: {
props: {},
data() {
return {
msg: "这里是组件的内容",
}
},
template: t1,
},
},
template: t2,
data() {
return {}
},
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 1.2 异步组件
- 通常页面很多子组件需要在一定条件下展示,页面性能有要求,可以使用异步组件对页面进行
按需加载
刷新
全屏/自适应
# 1.3 functional
- function 设置可以使组件无状态和无实例,也就是没有 data 和 this 上下文
- 内部没有逻辑交互(无 methods 方法、也没有 mounted 等任何生命周期处理函数),没有状态修改(无 data)
- 所有动态数据都从父组件传递进来(只有 props),数据变为常数,组件只用于展示数据
- v-once:模板编译时 ast 会做静态标记,
组件不会被更新
直接跳过
刷新
全屏/自适应
router-view 就是一个典型的 functional 组件
# 1.4 abstract
- 抽象组件和普通的组件类似,只是他们添加额外的行为,不向 DOM 呈现任何内容
- vue 中
component
、slot
、keep-alive
、transition
、transition-group
都是通过抽象组件实现的
# 1.4.1 防抖案例
<script>
import { get, debounce, set } from "loadsh"
export default {
name: "debounce",
abstract: true, //标记为抽象组件
render() {
let vnode = this.$slots.default[0] // 子组件的vnode
if (vnode) {
let event = get(vnode, `data.on.click`) // 子组件绑定的click事件
if (typeof event === "function") {
set(vnode, `data.on.click`, debounce(event, 1000))
}
}
return vnode
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1.4.2 component
- 动态切换不同类型的组件,动态表单中用的比较多
刷新
全屏/自适应
# 1.5 递归组件
递归组件就是组件在模板中调用自己,需要满足两个条件:
- 在组件中设置一个
name
选项,通过这个字段拿到组件 - 加上结束条件,防止一直递归下去,抛出
max stack size exeeded
错误
刷新
全屏/自适应
# 2.render
支持 jsx 写法,需要@vue/babel-preset-jsx 支持
render() {
return <p>hello</p>
}
1
2
3
2
3
# 2.1 render 函数
- template 写标签有时候不灵活,用 render 可以灵活处理标签
router-link 就是一个用 render 函数写的组件,详细分析可以看后面 render 专题分析
# 2.2 render 生成
<script>
var res = Vue.compile("<div><span>{{ msg }}</span></div>")
export default {
data: {
msg: "hello",
},
render: res.render,
staticRenderFns: res.staticRenderFns,
}
</script>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 3.Vnode
# 3.1 $createElement
- $createElement 最后会转到 render 函数中执行,这里使用比较灵活
刷新
全屏/自适应
# 4.element
- 将 vue 直接挂载到指定节点上
- 根结点在
new Vue({el:xxx})
也可以直接挂载
# 4.1 extend
- 一些项目中有些页面不是 vue 开发的(d3.js、echarts)等,某个地方需要写一些普通的页面,就可以中这种方式插入到指定 dom 元素下
刷新
全屏/自适应
extend 函数功能和 new Vue 类似,最后都会通过 this._init
初始化,通过$mount 挂载到指定节点
# 4.2 patch
- 将目标组件插入到指定 dom 下
- 这里实现的组件挂载功能与 Vue3.x 中的
Teleport
功能差不多
刷新
全屏/自适应
patch 函数执行后 Vue 内部会将 vnode 通过一系列的流程挂载到真实 dom 上
总结
通过上述案例分析可以在项目中灵活运用多种方式来挂载组件,更加灵活实现相关功能