vue 模板的本质是渲染函数
上節內容我們學習了 Vue 組件的本質?,這節內容看看 vue 模板的本質是什么。
模板 - 內容的承載體
Vue 在渲染組件的時候,需要使用者提供一個渲染模板或者渲染函數。渲染模板就是一個HTML字符串,中間加入了一些Vue特制的語法規則,這樣能夠讓 Vue 把數據和模板進行了綁定,當數據發生變化時會讓頁面能夠及時刷新。這節內容,我們學習一下 Vue 的模板及其本質。
數據綁定
通過雙大括號把屬性與模板進行綁定,當屬性變化時頁面也會實時更新。雙大括號中可以是:
data 或 props 中聲明的屬性;
計算屬性;
JS 表達式;
經過編譯后的渲染函數(render):
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_createVNode("div",?null,?_toDisplayString(_ctx.title),?1?/*?TEXT?*/),_createCommentVNode("?可接收?JS?表達式?"),_createVNode("div",?null,?_toDisplayString(_ctx.age?+?1),?1?/*?TEXT?*/),_createVNode("div",?null,?_toDisplayString(_ctx.age?>?18???'大朋友'?:?'小朋友'),?1?/*?TEXT?*/)],?64?/*?STABLE_FRAGMENT?*/)) }指令 v-if
v-if 指令如同編程語言中的 if 條件語句,使用方法可以參考編程語言中的 if 語句,根據不同的條件來渲染不同的模板。v-if 內容部分只要是一個表達式即可,可以使用 v-else-if 和 v-else。
<!--?v-if?條件渲染?--> <h1?v-if="age?<?18">我是小朋友</h1> <h1?v-else-if="age?>?18?&&?age?<?60">我是中年人</h1> <h1?v-else>我是老年人</h1>經過編譯后的渲染函數(render):
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_ctx.age?<?18)??(_openBlock(),?_createBlock("h1",?{?key:?0?},?"我是小朋友")):?(_ctx.age?>?18?&&?_ctx.age?<?60)??(_openBlock(),?_createBlock("h1",?{?key:?1?},?"我是中年人")):?(_openBlock(),?_createBlock("h1",?{?key:?2?},?"我是老年人")) }v-for 指令
如同編程語言中的 for 循環,用來循環創建一個模板,遍歷對象可以是數組或者對象。
<!--?for?指令,循環創建?--> <p?v-for="name?in?welcomes">{{?name?}}</p> <!--?in?和?of?等價?--> <p?v-for="name?of?welcomes">{{?name?}}</p> <p?v-for="(name,?index)?in?welcomes">{{?name?}}</p> <p?v-for="(name,?index)?in?welcomes"?:key="name.id">{{?name?}}</p> <!--?遍歷對象?--> <p?v-for="(value,?name)?in?myObject">{{?name?}}:?{{?value?}}</p>經過編譯后的渲染函數(render):
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[(_openBlock(true),?_createBlock(_Fragment,?null,?_renderList(_ctx.welcomes,?(name)?=>?{return?(_openBlock(),?_createBlock("p",?null,?_toDisplayString(name),?1?/*?TEXT?*/))}),?256?/*?UNKEYED_FRAGMENT?*/)),(_openBlock(true),?_createBlock(_Fragment,?null,?_renderList(_ctx.myObject,?(value,?name)?=>?{return?(_openBlock(),?_createBlock("p",?null,?_toDisplayString(name)?+?":?"?+?_toDisplayString(value),?1?/*?TEXT?*/))}),?256?/*?UNKEYED_FRAGMENT?*/))],?64?/*?STABLE_FRAGMENT?*/)) }class 綁定
可以給 HTML 元素綁定一個 class,也可以根據數據內容動態綁定一個 class。
<!--?class?--> <!--?動態綁定?class,當?isActive?為真時才會使用選擇器?active?--> <div?:class="{?active:?isActive?}">class1</div> <!--?可以綁定多個?--> <div?:class="{?active:?isActive,?selected:?isSelect}">class2</div> <!--?可直接通過一個對象來告訴?vue?該用哪個屬性,也就是把模板里的對象換個地方寫--> <div?:class="clsObj">class3</div> <!--?可使用多個對象,類似于數組?--> <div?:class="[clsObj,?clsObj2]">class4</div> <!--?直接使用三元表達式?--> <div?:class="[isActive???activeClass?:?'']">class5</div> <!--?還可以這樣用?--> <div?:class="[{?active:?isActive?},?errorClass]">class6</div> <!--?class?和??:class?可同時存在?--> <div?class="one-line"?:class="{?active:?isActive?}">class7</div>經過編譯后的渲染函數(render),通過渲染函數,你可以看到給元素設置 css 的本質:
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_createVNode("div",?{class:?{?active:?_ctx.isActive?}},?"class1",?2?/*?CLASS?*/),_createVNode("div",?{class:?{?active:?_ctx.isActive,?selected:?_ctx.isSelect}},?"class2",?2?/*?CLASS?*/),_createVNode("div",?{?class:?_ctx.clsObj?},?"class3",?2?/*?CLASS?*/),_createVNode("div",?{class:?[_ctx.clsObj,?_ctx.clsObj2]},?"class4",?2?/*?CLASS?*/),_createVNode("div",?{class:?[_ctx.isActive???_ctx.activeClass?:?'']},?"class5",?2?/*?CLASS?*/),_createVNode("div",?{class:?[{?active:?_ctx.isActive?},?_ctx.errorClass]},?"class6",?2?/*?CLASS?*/),_createVNode("div",?{class:?["one-line",?{?active:?_ctx.isActive?}]},?"class7",?2?/*?CLASS?*/)],?64?/*?STABLE_FRAGMENT?*/)) }style 綁定
style 綁定和 class 綁定語法規則基本一樣,它的作用是給元素通過 style 添加 css 樣式。
<!--?style?--> <div?:style="{?color:?activeColor,?fontSize:?fontSize?+?'px'?}">style1</div> <!--?直接使用對象?--> <div?:style="styleObject">style2</div> <!--?使用多個對象?--> <div?:style="[colorObj,?edgeObj]">style3</div> <!--?支持多個值?--> <div?:style="{?display:?['-webkit-box',?'-ms-flexbox',?'flex']?}">style4</div>經過編譯后的渲染函數(render)
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_createCommentVNode("?style?"),_createVNode("div",?{style:?{?color:?_ctx.activeColor,?fontSize:?_ctx.fontSize?+?'px'?}},?"style1",?4?/*?STYLE?*/),_createVNode("div",?{?style:?_ctx.styleObject?},?"style2",?4?/*?STYLE?*/),_createVNode("div",?{style:?[_ctx.colorObj,?_ctx.edgeObj]},?"style3",?4?/*?STYLE?*/),_createVNode("div",?{?style:?{?display:?['-webkit-box',?'-ms-flexbox',?'flex']?}?},?"style4")],?64?/*?STABLE_FRAGMENT?*/)) }事件
可通過 v-on 進行事件綁定,基本規則為 v-on:eventName,eventName 為 DOM 元素所支持的事件。v-on 可以簡寫換成 @
<!--?監聽事件?--> <button?v-on:click="clickMe">von</button> <!--?簡寫?--> <button?@click="clickMe">von</button> <!--?支持動態屬性名,?eventName?可動態變化,它的值可以是?click、focus--> <button?v-on:[eventName]="eventChange">von</button> <!--?指令的特殊修飾符,表示指令以某種特定的方式觸發?--> <form?v-on:submit.prevent="onSubmit">提交</form>經過編譯后的渲染函數(render)
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_createVNode("button",?{?onClick:?_ctx.clickMe?},?"von",?8?/*?PROPS?*/,?["onClick"]),_createVNode("button",?{?onClick:?_ctx.clickMe?},?"von",?8?/*?PROPS?*/,?["onClick"]),_createVNode("button",?{?[_toHandlerKey(_ctx.eventName)]:?_ctx.eventChange?},?"von",?16?/*?FULL_PROPS?*/),_createVNode("form",?{onSubmit:?_withModifiers(_ctx.onSubmit,?["prevent"])},?"提交",?40?/*?PROPS,?HYDRATE_EVENTS?*/,?["onSubmit"])],?64?/*?STABLE_FRAGMENT?*/)) }綁定屬性
無論是自定義組件還是 HTML標簽都可以通過 v-bind 把 DOM元素的屬性和數據屬性進行綁定。
<!--?通過?v-bind?來綁定屬性?--> <a?v-bind:href="url">點我</a> <!--?可簡寫?--> <a?:href="url">點我</a>經過編譯后的渲染函數(render)
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_createVNode("a",?{?href:?_ctx.url?},?"點我",?8?/*?PROPS?*/,?["href"]),_createVNode("a",?{?href:?_ctx.url?},?"點我",?8?/*?PROPS?*/,?["href"])],?64?/*?STABLE_FRAGMENT?*/)) }v-show 指令
控制元素的顯示隱藏,其原理是通過控制 css 屬性 display。它屬于自定義指令的范疇,你可以使用 Vue 提供的機制進行自定義指令。
<h1?v-show="isShow">Hello!</h1>經過編譯后的渲染函數(render),發現這個渲染函數與上面的都不一樣,它使用了 _withDirectives,這個是與指令相關的函數。
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?_withDirectives((_openBlock(),?_createBlock("h1",?null,?"Hello!",?512?/*?NEED_PATCH?*/)),?[[_vShow,?_ctx.isShow]]) }v-model 雙向綁定
與 v-show 指令一樣屬于自定義指令的范疇,最常用的場景是使用表單的時候,把用戶輸入的內容和數據進行雙向綁定。
<input?v-model="question"?/>經過編譯后的渲染函數(render)
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?_withDirectives((_openBlock(),?_createBlock("input",?{"onUpdate:modelValue":?$event?=>?(_ctx.question?=?$event)},?null,?8?/*?PROPS?*/,?["onUpdate:modelValue"])),?[[_vModelText,?_ctx.question]]) }v-html 指令
直接渲染 HTML 字符串,HTML 不被看做是文本,它會當做 HTML 渲染到頁面上。
<div?v-html="html">v-html</div>經過編譯后的渲染函數(render)
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock("div",?{?innerHTML:?_ctx.html?},?null,?8?/*?PROPS?*/,?["innerHTML"])) }v-once 指令
只修改一次,即使數據以后更新了,頁面也不會自動更新。
<div?v-once>{{?from?}}</div>經過編譯后的渲染函數(render)
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?_cache[1]?||?(_setBlockTracking(-1),_cache[1]?=?_createVNode("div",?null,?_toDisplayString(_ctx.from),?1?/*?TEXT?*/),_setBlockTracking(1),_cache[1]) }最后
本節內容我們重點學習了各個模板的語法規則,以及各個指令的作用。在介紹模板時,也給大家演示了最終生成的渲染函數,有助于大家理解模板的本質。
模板的本質其實就是渲染函數;渲染函數的本質其實就是操作虛擬DOM;虛擬DOM的本質其實就是操作真正的 DOM;最終達到通過 JS 操作真正的 DOM,以讓頁面動態更新;
渲染函數
本節內容同步在網站 https://lefex.gitee.io/ 上,我會把大家的問題匯總到網站上。大家加油!!
長按關注
素燕《前端小課》
幫助 10W 人入門并進階前端
官網:https://lefex.gitee.io/
總結
以上是生活随笔為你收集整理的vue 模板的本质是渲染函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mySQL全指令学习记录
- 下一篇: Element UI 与 Vuetify