前言
在之前的文章中我整理了一些Vue的核心:数据代理、数据劫持、依赖收集、视图更新、diff。Vue的有趣和强大当然不止于此,接下来我会通过一些实践来整理Vue2的其他功能、特性。
通过前面的代码,其实我们能发现,使用Vue2来开发最终还是要通过JS实现的。所以这一节我们来使用JS函数实现一个Dialog,目的是手动地挂载这个组件,使它能在项目中的任何页面上调用。
基础
Dialog组件
xml
<!-- /src/components/Dialog.vue -->
<template>
<div class="container">
<div>{{ text }}</div>
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
default: ''
}
},
}
</script>
调用函数
javascript
// /src/utils/dialog.js
import Vue from "vue";
import Dialog from "@/components/Dialog.vue";
let DialogContructor = Vue.extend(Dialog);
export default function openDialog(options) {
const instance = new DialogContructor({
props: {
text: options.text,
},
render(h) {
return h(Dialog, {
props: {
text: this.text
}
})
}
})
document.body.appendChild(instance.$mount().$el); // 手动将实例化的元素挂载到body上
}
使用
xml
<!-- 组件A -->
<template>
<!-- 省略 -->
</template>
<script>
import openDialog from '@/uitls/dialog';
export default {
// ...
methods: {
click() {
openDialog({
text: 'Hi~Vue2'
})
}
}
}
</script>
通过以上代码已经可以实现这个简单的功能了
进阶-在Dialog中使用slot
使用slot的组件可以给使用者提供更灵活的调用,比如Dialog
有时候仅仅用作一个消息通知,有时候又可以模拟一个弹出输入框。
xml
<!-- /src/components/Dialog.vue -->
<template>
<div class="container">
<div class="title">{{ title }}</div>
<div class="content">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
}
},
}
</script>
xml
<!-- 组件A -->
<template>
<!-- 省略 -->
</template>
<script>
import openDialog from '@/uitls/dialog';
import TextInput from '@/components/FieldTypes/TextInput.vue';
export default {
// ...
methods: {
click() {
openDialog({
title: 'Hi~Vue2',
components: {
TextInput
},
slotRender: (h) => {
props: {
field: {
type: 'text',
name: '选项名称',
placeholder: '请输入选项名称',
required: true,
value: ''
}
},
}
})
}
}
}
</script>
在openDialog中传入的options最终在dialog.js
中进行处理
javascript
// /src/utils/dialog.js
import Vue from "vue";
import Dialog from "@/components/Dialog.vue";
let DialogContructor = Vue.extend(Dialog);
export default function openDialog(options) {
const instance = new DialogContructor({
props: {
title: options.title,
},
components: options.components || {},
render(h) {
const slot = slotRender ? slotRender(h) : null;
return h(Dialog, {
props: {
text: this.text
},
scopedSlots: {
default: () => slot
}
})
}
})
document.body.appendChild(instance.$mount().$el); // 手动将实例化的元素挂载到body上
}
通过这样的方式,我们在组件中可以更灵活地使用这个函数调用组件,往其中塞入自定义的组件结构
进阶-函数调用组件的组件间通信
想要完成组件间通信很重要的一点在于运用JS的引用类型特性、以及$emits
API。前者不需要特别赘述,但是$emits
API在这里的使用值得注意:
首先我们假设TextInput
中已经有$emit('input', $event.target.value)
xml
<!-- 组件A -->
<template>
<!-- 省略 -->
</template>
<script>
import openDialog from '@/uitls/dialog';
import TextInput from '@/components/FieldTypes/TextInput.vue';
export default {
// ...
data() {
return {
componentData: {}
}
}
methods: {
click() {
openDialog({
title: 'Hi~Vue2',
components: {
TextInput
},
slotRender: (h) => {
props: {
field: {
type: 'text',
name: '选项名称',
placeholder: '请输入选项名称',
required: true,
value: ''
}
},
on: {
'input': (value) => formData['text'] = value
}
}
})
}
}
}
</script>
javascript
// /src/utils/dialog.js
import Vue from "vue";
import Dialog from "@/components/Dialog.vue";
let DialogContructor = Vue.extend(Dialog);
export default function openDialog(options) {
const instance = new DialogContructor({
props: {
title: options.title,
},
components: options.components || {},
render(h) {
const slot = slotRender ? slotRender(h) : null;
return h(Dialog, {
props: {
text: this.text
},
on: {
'custom-confirm': options.methods.confirm
},
scopedSlots: {
default: () => slot
}
})
}
})
document.body.appendChild(instance.$mount().$el); // 手动将实例化的元素挂载到body上
}
xml
<!-- /src/components/Dialog.vue -->
<template>
<div class="container">
<div class="title">{{ title }}</div>
<div class="content">
<slot></slot>
</div>
<div class="actions">
<button class="confirm" @click="confirm">确定</button>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
}
},
methods: {
confirm () {
this.$emit('custom-confirm')
},
}
}
</script>
这里其实通过了两个$emits
事件以及引用类型特性,完成了函数调用组件的通信。
总结
根据这个例子,后续会展开整理一下内容:
Vue.extend()
API- Vue源码对methods以及事件的处理,补全实例化Vue的一些内容
- 手写渲染函数
下一个实例的话会选择动态表单这个经典案例