复习vue19、渲染函数
Vue
推荐在绝大数情况下使用模板来创建你的HTML
。然后在一些场景中,你真的需要JavaScript
的完全编程的能力,也就是使用javaScript来创建HTML
,这时你可以用渲染函数,它比模板更接近编译器。
这里我们先来做一个基本的了解,为后期的深入学习打好一个基础。
下面先看一下render
函数的基本结构。
render:function(createElement){
//createElement函数返回的结果为VNode. VNode就是虚拟dom,用js对象来模拟真实的DOM.
retrun createElement(
tag, //标签名称
data,// 传递数据
children //子节点数组
)
}
下面我们在用户管理这个案例中,使用render
函数来创建一个组件。
具体的代码如下:
// heading组件
//<heading :level="1">{{title}}</heading> //这时要创建的组件
// <h2 title=""></h2> //这时上面的组件最终渲染的结果
Vue.component("heading", {
props: {
level: {
type: String,
required: true,
},
},
render(h) { //h 就是createElement函数
return h(
"h" + this.level, //参数1,表示要创建的元素
this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个子元素)
);
},
});
接下来就可以使用heading
组件了。
<!-- 使用render函数创建的头部组件 -->
<heading level="1">
{{title}}
</heading>
当然,这里需要在data
中定义title
属性
data: {
num: 100,
totalCount: 0,
users: [],
height: 0,
userInfo: "abc",
title: "用户管理",
// isShow: false,
// showWarn: false, // 控制警告窗口的显示与隐藏
},
完整代码如下(24、render函数.html
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>列表渲染</title>
<style>
.actived {
background-color: #dddddd;
}
.message-box {
padding: 10px 20px;
}
.success {
background-color: #4fc;
border: 1px solid #42b;
}
.warning {
background-color: red;
border: 1px solid #42b;
}
.message-box-close {
float: right;
}
</style>
</head>
<body>
<div id="app">
<!-- 弹窗组件 -->
<message ref="msgSuccess" class="success">
<!-- titile的插槽 -->
<template v-slot:title>
<h2>恭喜</h2>
</template>
<!-- 默认插槽 -->
<template>
添加用户成功
</template>
</message>
<!-- 警告 -->
<message ref="msgWaring" class="warning">
<!-- titile的插槽 -->
<template v-slot:title>
<h2>警告</h2>
</template>
<!-- 默认插槽 -->
<template>
请输入用户名
</template>
</message>
<!-- 使用render函数创建的头部组件 -->
<heading level="1">
{{title}}
</heading>
<!-- 清空提示栏 -->
<div class="toolbar">
<button @click="$bus.$emit('message-close')">
清空提示栏
</button>
</div>
<!-- 批量更新身高 -->
<p>
<input type="text" v-model.number="height" />
<button @click="batchUpdate">批量更新用户身高</button>
</p>
<!-- 新增用户 -->
<user-add @add-user="addUser" v-model="userInfo"></user-add>
<!-- 用户列表组件 -->
<user-list :users="users"></user-list>
<p>
总人数:{{totalCount}}
</p>
</div>
<script src="vue.js"></script>
<script>
//创建事件总线
Vue.prototype.$bus = new Vue();
// heading组件
//<heading :level="1">{{title}}</heading> //这时要创建的组件
// <h2 title=""></h2> //这时上面的组件最终渲染的结果
Vue.component("heading", {
props: {
level: {
type: String,
required: true,
},
},
render(h) {
return h(
"h" + this.level, //参数1,表示要创建的元素
this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个子元素)
);
},
});
//创建弹出的组件
Vue.component("message", {
//show表示的含义,控制弹出窗口的显示与隐藏。
//slot:表示占坑。也就是窗口中的内容,是通过外部组件传递过来的。
// props: ["show"],
data() {
return {
show: false,
};
},
template: `<div class='message-box' v-if="show">
<!--具名插槽-->
<slot name="title">默认标题</slot>
<slot></slot>
<span class="message-box-close" @click='toggle'>关闭</span>
</div>`,
mounted() {
//给总线绑定`message-close`事件
//也就是监听是否有`message-close`事件被触发。
this.$bus.$on("message-close", () => {
// this.$emit("close", false);
//当警告窗口和提示信息的窗口,展示出来了才关闭。
if (this.show) {
this.toggle();
}
});
},
methods: {
toggle() {
this.show = !this.show;
},
},
});
//新增用户组件
Vue.component("user-add", {
// data() {
// return {
// userInfo: "",
// };
// },
props: ["value"],
template: `
<div>
<p>
<input type="text" :value="value" @input="onInput" v-on:keydown.enter="addUser" ref="inp" />
</p>
<button @click="addUser">新增用户</button>
</div>
`,
methods: {
addUser() {
//将输入的用户数据通知给父组件,来完成新增用户操作.
// this.$emit("add-user", this.userInfo);
this.$emit("add-user");
// this.userInfo = "";
},
onInput(e) {
this.$emit("input", e.target.value);
},
},
mounted() {
this.$refs.inp.focus();
},
});
// 用户列表
Vue.component("user-list", {
data() {
return {
selectItem: "",
};
},
props: {
users: {
type: Array,
default: [],
},
},
template: `
<div>
<p v-if="users.length===0">没有任何用户数据</p>
<ul v-else>
<li
v-for="(item,index) in users"
:key="item.id"
:style="{backgroundColor:selectItem===item?'#dddddd':'transparent'}"
@mousemove="selectItem=item"
>
编号:{{item.id}} 姓名:{{item.name}}---身高:{{item.height}}
</li>
</ul>
</div>
`,
});
new Vue({
el: "#app",
data: {
num: 100,
totalCount: 0,
users: [],
height: 0,
userInfo: "abc",
title: "用户管理",
// isShow: false,
// showWarn: false, // 控制警告窗口的显示与隐藏
},
//组件实例已创建时
async created() {
const users = await this.getUserList();
this.users = users;
//批量更新用户身高
this.batchUpdate();
},
methods: {
//关闭窗口
closeWindow(data) {
this.isShow = data;
this.showWarn = data;
},
//添加用户的信息
addUser() {
if (this.userInfo) {
if (this.users.length > 0) {
this.users.push({
id: this.users[this.users.length - 1].id + 1,
name: this.userInfo,
});
this.userInfo = "";
//完成用户添加后,给出相应的提示信息
// this.isShow = true;
this.$refs.msgSuccess.toggle();
}
} else {
// 显示错误警告信息
// this.showWarn = true;
this.$refs.msgWaring.toggle();
}
},
//批量更新身高,动态的给users中添加身高属性
batchUpdate() {
this.users.forEach((c) => {
// c.height = this.height;
// Vue.set(c, "height", this.height);
this.$set(c, "height", this.height);
});
},
getTotal: function () {
console.log("methods");
return this.users.length + "个";
},
getUserList: function () {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{
id: 1,
name: "张三",
},
{
id: 2,
name: "李四",
},
{
id: 3,
name: "老王",
},
]);
}, 2000);
});
},
},
watch: {
users: {
immediate: true, //立即执行
handler(newValue, oldValue) {
this.totalCount = newValue.length + "个人";
},
},
},
});
</script>
</body>
</html>
虚拟DOM
Vue
通过建立一个虚拟DOM来追踪自己要如何改变真实DOM
.
createElement
参数
前面说过,createElement
函数有三个参数。
createElement(
//{string |Object|Function}
//第一个参数,可以是字符串,也可以是对象或者是函数
‘div’
,
// 第二个参数是对象,表示的是一个与模板中属性对应的数据对象。该参数可选
{
},
//第三个参数是一个数组,表示的是子节点数组
[
]
)
下面,给heading
组件添加第一个属性。
<!-- 使用render函数创建的头部组件 -->
<heading level="1" :title="title">
{{title}}
</heading>
在上面的代码中,我们给heading
组件动态添加了一个title
属性。而我们知道heading
组件,最终渲染成的是h1
的元素,最终效果为:<h1 title='aaa'>
的形式。
// heading组件
//<heading :level="1">{{title}}</heading> //这时要创建的组件
// <h2 title=""></h2> //这时上面的组件最终渲染的结果
Vue.component("heading", {
props: {
level: {
type: String,
required: true,
},
title: {
type: String,
default: "",
},
},
render(h) {
return h(
"h" + this.level, //参数1,表示要创建的元素
{ attrs: { title: this.title } }, //参数2
this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个子元素)
);
},
});
在上面的代码中,我们在render
函数中给h
函数添加了第二个参数,给最终生成的元素添加了attrs
属性。