提要
要动态挂载一个Vue组件Component,就必须实例化一个Vue对象,指定渲染函数和挂载位置。
而不能直接向document写入html代码的方式插入DOM,这不会触发Vue框架的渲染。
和挂载App一样:
import Vue from 'vue';
import App from './App.vue';
new Vue({
render: h => h(App);
}).$mount('#app');
其中h是function (createElement, context)
中的createElement
。render其实应该这样写:
render: function (createElement, context) {
return createElement(App);
}
将 h 作为 createElement 的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。
文档:https://cn.vuejs.org/v2/guide/render-function.html
函数式使用组件
以下文件实现了一个全屏的提示框组件,要弹出这个提示框,可以往页面某个占位div上挂载:
new Vue({
render: h => h(FrameAlert),
}).$mount($(document.body)[0])
等等,参数、事件怎么传递呢?
组件需要的一切都是通过 context 参数传递,那么如果我们传递给createElement的第一个参数是一个单文件导出的组件对象,
可以直接将 context 作为第二个参数,会成功到达该单文件组件的render函数!
context是一个包括如下字段的对象:
props:提供所有 prop 的对象
children: VNode 子节点的数组
slots: 一个函数,返回了包含所有插槽的对象
scopedSlots: (2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。
data:传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件
parent:对父组件的引用
listeners: (2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on 的一个别名。
injections: (2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性。
划重点!以下字段你很难在文档中找到,但却经常需要使用
on:事件
domProps:dom参数
所以,我们这样传递参数和事件:
new Vue({
render: h => h(FrameAlert, {
props: { msg: '提示' },
on: { click(event) { console.log(event.target.innerText); }, },
}),
}).$mount($(document.body)[0])
文件:FrameAlert.vue
<template>
<div class="frame_alert">
<div class="alert">
<div class="msg">
<div>
<span v-html="filtedMsg"></span>
</div>
</div>
<div class="buttons">
<hr>
<div class="btnwrapper">
<span @click=handle class="button" href="#">确定</span><span @click=handle class="button" href="#">取消</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: "Message in here...",
},
},
data() {
return {
};
},
computed: {
filtedMsg() {
return this.filteMsg(this.msg);
},
},
methods: {
handle(event) {
this.$emit('click', event);
},
filteMsg(msg) {
return msg.replace(/</g, '<').replace(/>/g, '>').replace(/(?:
|\n)/g, '<br>');
}
},
mounted() {
},
}
</script>
<style scoped>
.frame_alert {
position: fixed;
top: 0;
100%;
height: 100%;
padding: 0;
margin: 0;
background: rgba(0, 0, 0, 0.8);
}
.alert {
/* 外观 */
fit-content;
min- 300px;
max- 60%;
border-radius: 15px;
background: white;
color: black;
word-break: break-all;
/* 定位 */
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
}
.msg {
max-height: 200px;
margin: 20px;
margin-bottom: 80px;
overflow: auto;
text-align: center;
font-size: 22px;
}
.msg::-webkit-scrollbar {
/*隐藏滚轮*/
display: none;
}
.buttons {
position: fixed;
margin: 0;
bottom: 0;
100%;
height: 60px;
margin: auto;
border-radius: 0 0 15px 15px;
}
.btnwrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
80%;
margin-top: 2px;
}
.button {
text-align: center;
font-size: 22px;
display: inline-block;
50%;
margin: 0;
padding: 0;
color: blue;
text-decoration: none;
cursor: pointer;
user-select: none;
}
.button:active {
text-shadow: 1px 1px 10px;
}
</style>