页面模板和render函数
Vue
对象构建时需要为对象指定页面构成结构,该构成结构称之为模板
在基本构成
vue
对象时通过
mount(el)
指定
构成的页面模板,同时指定页面位置
1
、模板属性
(template)
Vue
实例添加
template
属性,可以独立定义页面构成模板
template
构成的模板
最终会替换到
mount(el)
的指向位置
示例
:
StringDOM
:
HTML
标签的字符串定义方式
StringEl
:
HTML
元素选择器
?// 单一职能原则 => 代码中一个定义只用于描述一个功能
? ? ? ? // ? ? ? ? ? ? => 一个文件的代码组成只用于解决一类问题
? ? ? ? // ? ? ?优点:文件功能独立相互关联引用,但互不干扰,可以快速替换和修改、可以快速复用
? ? ? ? // ? ? ?缺点:调用链长,中途接收开发困难
? ? ? ? // vue的容器构建时,页面定义的代码不是最终呈现的DOM
? ? ? ? /*
? ? ? ? Vue实例添加 template 属性,可以独立定义页面构成模板
? ? ? ? vue容器构建步骤:
? ? ? ? ? ? 1.读取容器代码结构 => template
? ? ? ? ? ? 2.渲染代码结构为真实响应式DOM => render
? ? ? ? ? ? 3.将真实响应式DOM写入到页面对应的位置进行展示 => mount(el)
? ? ? ? template 构成的模板 最终会替换到 mount(el) 指向元素的内容
? ? ? ? 示例:
? ? ? ? ? ? Vue.createApp({,
? ? ? ? ? ? ? ? template:StringDOM | StringEl
? ? ? ? ? ? }).mount("#app")
? ? ? ? ? ? + StringDOM:HTML标签的字符串定义方式
? ? ? ? ? ? + StringEl:HTML元素选择器
<div id="app">
<h1>测试template优先级</h1>
</div>
<hr>
<!-- 模板第一种定义方案 -->
<!-- <div id="root" style="display: none;">
<h5>页面root模板-div</h5>
<p>msg:{{ msg }}</p>
<input type="text" v-model="msg">
</div> -->
<!-- 模板第二种定义方案 -->
<!-- <template id="root">
<h5>页面root模板-template</h5>
<p>msg:{{ msg }}</p>
<input type="text" v-model="msg">
</template> -->
<!-- 模板第三种定义方案 -->
<script type="text/x-template" id="root">
<h5>页面root模板-script</h5>
<p>msg:{{ msg }}</p>
<input type="text" v-model="msg">
</script>
<script type="module">
// 单一职能原则 => 代码中一个定义只用于描述一个功能
// => 一个文件的代码组成只用于解决一类问题
// 优点:文件功能独立相互关联引用,但互不干扰,可以快速替换和修改、可以快速复用
// 缺点:调用链长,中途接收开发困难
// vue的容器构建时,页面定义的代码不是最终呈现的DOM
/*
Vue实例添加 template 属性,可以独立定义页面构成模板
vue容器构建步骤:
1.读取容器代码结构 => template
2.渲染代码结构为真实响应式DOM => render
3.将真实响应式DOM写入到页面对应的位置进行展示 => mount(el)
template 构成的模板 最终会替换到 mount(el) 指向元素的内容
示例:
Vue.createApp({,
template:StringDOM | StringEl
}).mount("#app")
+ StringDOM:HTML标签的字符串定义方式
+ StringEl:HTML元素选择器
*/
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
createApp({
// template:`
// <p>msg:{{ msg }}</p>
// <input type="text" v-model="msg">
// `,
template:"#root",
data(){
return {
msg:"msg测试数据"
}
}
}).mount("#app")
</script>
2、模板渲染函数(render)
Vue
实例添加
render
属性函数,可以独立定义
JS
模板构成函数
render
构成的模板具有
==
最高优先权,
最终会替换到
mount(el)
的指向位置
==
,且
template
属性失效
示例
:
render
属性取值为一个函数,该函数返回构成的模板
Vue.h
为渲染函数,
该参数可用于以方法方式构建页面模板
<div id="app"></div>
<script>
// 1、提供页面结构 => template
let htmlTemplate = `
<p>msg:{{ msg }}</p>
<input type="text" v-model="msg">
`;
let data = {
msg:"测试msg"
}
// 1.1 字符串到dom的转换
let domBox = document.createElement("div");
domBox.innerHTML = htmlTemplate;
// console.log(domBox);
let list = domBox.childNodes
console.log(list);
// JS 内存dom虚拟容器盒子
let tempBox = document.createDocumentFragment();
list.forEach(item=>{
// console.log(item,item.cloneNode(true));
// 2、渲染节点 => render
// 递归函数 => vue的语法解析 => 响应式关联
let cloneNode = item.cloneNode(true)
let text = cloneNode.textContent;
let flag = text.match(/{{\s*([^\s]*)\s*}}/);
if(flag!=null){
cloneNode.textContent = text.replace(/{{\s*([^\s]*)\s*}}/,data[flag[1]])
}
tempBox.appendChild( cloneNode )
})
// 3、把转换的DOM节点渲染到页面 => mount(el)
let htmlBox = document.querySelector("#app")
// console.log(htmlBox);
htmlBox.appendChild(tempBox)
</script>
3、虚拟DOM
Vue
.
createApp
({,
template
:
StringDOM
|
StringEl
}).
mount
(
"#app"
)
Vue
.
createApp
({
data
:{
title
:
"
标题
"
},
render
:
function
() {
return
Vue
.
h
(
'h4'
,
'render'
+
this
.
title
);
}
}).
mount
(
"#app"
)
Vue
引入了虚拟
DOM
和
DIFF
算法提示渲染性能
虚拟
DOM
的存在就是为了提高程序运行性能;
虚拟
DOM
实际就是一个存在于内存中的数据对象,可以用于描述一个
DOM
结构
浏览器对于
DOM
元素的直接操作效率较低,但对于
JS
的内存数据操作效率较
高
浏览器对于
DOM
的操作是非智能操作,每一次的调用都会重新渲染该
DOM
对象
(
回流、重绘
)
JS
数据变量的赋值,可以有效确定值是否真的发生了变化,如果是才会修改
内存结果
diff
算法
内存中的数据变量发生变化,页面
DOM
元素需要进行更新
<body>
<div id="app">
</div>
<script type="module">
import { createApp,h,createVNode } from "../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
msg:"测试MSG变量关联"
}
},
render(vm) {
console.log(vm,this);
// console.log(h);
// h 是vue在render函数中提供的用于完成响应式关联的DOM构建工具
// return "<h4>测试数据</h4>"
// return h("h4","render函数模板:"+vm.msg)
return h("div",[
"容器",
h("h4","render函数模板:"+vm.msg),
h("input",{ type:"text",value:vm.msg,onInput:(event)=>{ vm.msg = event.target.value } })
])
},
}).mount("#app")
</script>
?
?
生命周期
生命周期:一段代码从 创建 到 销毁的 完成过程
钩子函数
: Vue
对外提供的在一些特点代码执行段上的回调函数
Vue
.
createApp
({
//
在实例初始化之后,数据观测 和 事件配置之前被调用。
beforeCreate
:
function
(){},
//
在实例创建完成后被立即调用
created
:
function
(){},
//
在挂载开始之前被调用:相关的
render
函数首次被调用。
beforeMount
:
function
(){},
// el
被新创建的
vm.$el
替换,并挂载到实例上去之后调用该钩子
mounted
:
function
(){},
//
数据更新时调用,发生在虚拟
DOM
打补丁之前。这里适合在更新之前访问现
有的
DOM
beforeUpdate
:
function
(){},
//
由于数据更改导致的虚拟
DOM
重新渲染和打补丁,在这之后会调用该钩子。
updated
:
function
(){},
//
实例销毁之前调用。在这一步,实例仍然完全可用。
beforeUnmount
:
function
(){},
// Vue
实例销毁后调用。调用后,
Vue
实例指示的所有东西都会解绑定,所有
的事件监听器会被移除
unmounted
:
function
(){},
//
特殊生命周期监听函数
renderTracked
:
function
({
key
,
target
,
type
}) {},
renderTriggered
:
function
({
key
,
target
,
type
}) {},
});
生命周期流程
<div id="app">
<div>
<p ref="pDom">msg:{{ msg }}</p>
<input type="text" v-model="msg">
<p>info:{{ info }}</p>
<input type="text" v-model="info">
<br><br>
<input type="button" value="销毁" @click="unmountCallback()">
</div>
</div>
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
let app = createApp({
data(){
return {
msg:"msg数据",
info:"info数据"
}
},
methods: {
unmountCallback(){
app.unmount()
}
},
beforeCreate() {
console.group("beforeCreate=====>")
console.log("vue实例构建完成,vue环境构建完成");
console.log("$data:",this.$data); // {}
console.log("msg:",this.msg); // undefined
console.groupEnd();
},
// 应用:在vue项目运行时用于初始化数据的请求(ajax数据加载)-最早的初始化数据加载生命周期钩子函数
// 特殊vue运行环境(SSR):服务端渲染初始数据的加载最好是在created生命周期中完成
// ==> SSR 可以提供更好的 SEO(搜索引擎优化-就是爬虫-不执行css和js)
// ==> SSR 首屏(第一个页面) 效率根高 (一个优秀的知识宣传网站不超过8屏[8个屏幕大小])
created() {
console.group("created=====>")
console.log("运行依赖的加载,响应式功能的构成");
console.log("$data:",this.$data); // Proxy?{msg: 'msg数据'}
console.log("msg:",this.msg); // 'msg数据'
console.groupEnd();
},
beforeMount() {
console.group("beforeMount=====>")
console.log("加载和编译模板结构,生成虚拟DOM树(JS对象)=>绑定响应数据=>引入diff算法");
console.log("$el:",this.$el); // null
console.log("$refs.pDom:",this.$refs.pDom); // undefined
console.groupEnd();
},
// 应用:需要基于页面元素进行初始化构建的相关操作,都会在mounted进行调用
// 该构造函数是vue自动化执行的初始方法中的最后一个,且上述生命周期构子函数只会执行一次
mounted() {
console.group("mounted=====>")
console.log("基于虚拟节点(vnode)构建的带有响应式功能的真实DOM树,已完成创建和页面写入");
console.log("$el:",this.$el); // 页面最终容器DOM
console.log("$refs.pDom:",this.$refs.pDom); // 页面最终的元素
console.groupEnd();
},
// 被动监控变量更新后的 vnode操作和DOM更新
beforeUpdate() {
console.group("beforeUpdate=====>")
console.log("数据仓库变量已被修改,DOM尚未更新");
console.log("$data:",this.$data);
console.log("$refs.pDom.textContent:",this.$refs.pDom.textContent);
console.groupEnd();
},
updated() {
console.group("updated=====>")
console.log("基于diff算法的vnode更新完成,同时DOM渲染完成");
console.log("$data:",this.$data);
console.log("$refs.pDom.textContent:",this.$refs.pDom.textContent);
console.groupEnd();
},
// vue3的销毁构造函数
beforeUnmount() {
console.group("beforeUnmount=====>")
console.log("开始销毁");
console.groupEnd();
},
unmounted() {
console.group("unmounted=====>")
console.log("销毁完成");
console.groupEnd();
},
// vue2的销毁构造函数
// beforeDestroy() {
// },
// destroyed() {
// },
});
// setTimeout(() => {
// app.mount("#app")
// }, 5000);
app.mount("#app")
</script>
<div id="app">
<div class="swiper-container" ref="loop">
<div class="swiper-wrapper">
<div class="swiper-slide">slider1</div>
<div class="swiper-slide">slider2</div>
<div class="swiper-slide">slider3</div>
</div>
</div>
<hr>
<pre>请求结果:{{ result }}</pre>
</div>
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
result:{}
}
},
methods: {
initSwiper(){
new Swiper(this.$refs.loop, {
autoplay: 5000,//可选选项,自动滑动
})
},
loadInitData(){
axios.get("http://127.0.0.1:3000/public/user")
.then(( response )=>{
console.log( response.data );
this.result = response.data
})
.catch(()=>{
alert("请求失败")
})
}
},
created() {
this.loadInitData();
},
mounted() {
// 不要在生命周期构子函数中定义大量的逻辑执行代码
// 以方法方式分解功能,通过实例进行调用
// new Swiper(this.$refs.loop, {
// autoplay: 5000,//可选选项,自动滑动
// })
// this.loadInitData();
this.initSwiper();
},
}).mount("#app")
</script>
|