vue?parseHTML函數(shù)源碼解析start鉤子函數(shù)
正文
接上章節(jié):parseHTML 函數(shù)源碼解析 AST 預(yù)備知識(shí)
現(xiàn)在我們就可以愉快的進(jìn)入到Vue start鉤子函數(shù)源碼部分了。
start: function start(tag, attrs, unary) { // check namespace. // inherit parent ns if there is one var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag); // handle IE svg bug /* istanbul ignore if */ if (isIE && ns === 'svg') { attrs = guardIESVGBug(attrs); } var element = createASTElement(tag, attrs, currentParent); if (ns) { element.ns = ns; } if (isForbiddenTag(element) && !isServerRendering()) { element.forbidden = true; warn$2( 'Templates should only be responsible for mapping the state to the ' + 'UI. Avoid placing tags with side-effects in your templates, such as ' + "<" + tag + ">" + ', as they will not be parsed.' ); } // apply pre-transforms for (var i = 0; i < preTransforms.length; i++) { element = preTransforms[i](element, options) || element; } if (!inVPre) { processPre(element); if (element.pre) { inVPre = true; } } if (platformIsPreTag(element.tag)) { inPre = true; } if (inVPre) { processRawAttrs(element); } else if (!element.processed) { // structural directives processFor(element); processIf(element); processOnce(element); // element-scope stuff processElement(element, options); } function checkRootConstraints(el) { { if (el.tag === 'slot' || el.tag === 'template') { warnOnce( "Cannot use <" + (el.tag) + "> as component root element because it may " + 'contain multiple nodes.' ); } if (el.attrsMap.hasOwnProperty('v-for')) { warnOnce( 'Cannot use v-for on stateful component root element because ' + 'it renders multiple elements.' ); } } } // tree management if (!root) { root = element; checkRootConstraints(root); } else if (!stack.length) { // allow root elements with v-if, v-else-if and v-else if (root.if && (element.elseif || element.else)) { checkRootConstraints(element); addIfCondition(root, { exp: element.elseif, block: element }); } else { warnOnce( "Component template should contain exactly one root element. " + "If you are using v-if on multiple elements, " + "use v-else-if to chain them instead." ); } } if (currentParent && !element.forbidden) { if (element.elseif || element.else) { processIfConditions(element, currentParent); } else if (element.slotScope) { // scoped slot currentParent.plain = false; var name = element.slotTarget || '"default"'; (currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element; } else { currentParent.children.push(element); element.parent = currentParent; } } if (!unary) { currentParent = element; stack.push(element); } else { closeElement(element); } }
如上代碼start 鉤子函數(shù)接受三個(gè)參數(shù),這三個(gè)參數(shù)分別是標(biāo)簽名字 tag,該標(biāo)簽的屬性數(shù)組attrs,以及代表著該標(biāo)簽是否是一元標(biāo)簽的標(biāo)識(shí) unary。
接下來(lái)別害怕看不懂,我們一點(diǎn)點(diǎn)來(lái)分析它函數(shù)體中的代碼。
var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);
開(kāi)頭定義了 ns 變量,它的值為標(biāo)簽的命名空間,如何獲取當(dāng)前元素的命名空間呢?首先檢測(cè)currentParent 變量是否存在,我們知道 currentParent 變量為當(dāng)前元素的父級(jí)元素描述對(duì)象,如果當(dāng)前元素存在父級(jí)并且父級(jí)元素存在命名空間,則使用父級(jí)的命名空間作為當(dāng)前元素的命名空間。
如果父級(jí)元素不存在或父級(jí)元素沒(méi)有命名空間那么會(huì)調(diào)用platformGetTagNamespace函數(shù),platformGetTagNamespace 函數(shù)只會(huì)獲取 svg 和 math 這兩個(gè)標(biāo)簽的命名空間,但這兩個(gè)標(biāo)簽的所有子標(biāo)簽都會(huì)繼承它們兩個(gè)的命名空間。
platformGetTagNamespace 源碼
function getTagNamespace(tag) { if (isSVG(tag)) { return "svg" } if (tag === "math") { return "math" } }
接下來(lái)源碼:
if (isIE && ns === "svg") { attrs = guardIESVGBug(attrs); }
這里通過(guò)isIE來(lái)判斷宿主環(huán)境是不是IE瀏覽器,并且前元素的命名空間為svg, 如果是通過(guò)guardIESVGBug處理當(dāng)前元素的屬性數(shù)組attrs,并使用處理后的結(jié)果重新賦值給attrs變量,該問(wèn)題是svg標(biāo)簽中渲染多余的屬性,如下svg標(biāo)簽:
<svg xmlns:feature="http://www.openplans.org/topp"></svg>
被渲染為:
<svg xmlns:NS1="" NS1:xmlns:feature="http://www.openplans.org/topp"></svg>
標(biāo)簽中多了 'xmlns:NS1="" NS1:' 這段字符串,解決辦法也很簡(jiǎn)單,將整個(gè)多余的字符串去掉即可。而 guardIESVGBug 函數(shù)就是用來(lái)修改NS1:xmlns:feature屬性并移除xmlns:NS1="" 屬性的。
接下來(lái)源碼:
var element = createASTElement(tag, attrs, currentParent); if (ns) { element.ns = ns; }
在上章節(jié)聊過(guò),createASTElement 它將生成當(dāng)前標(biāo)簽的元素描述對(duì)象并且賦值給 element 變量。緊接著檢查當(dāng)前元素是否存在命名空間 ns ,如果存在則在元素對(duì)象上添加 ns 屬性,其值為命名空間的值。
接下來(lái)源碼:
if (isForbiddenTag(element) && !isServerRendering()) { element.forbidden = true; warn$2( 'Templates should only be responsible for mapping the state to the ' + 'UI. Avoid placing tags with side-effects in your templates, such as ' + "<" + tag + ">" + ', as they will not be parsed.' ); }
這里的作用就是判斷在非服務(wù)端渲染情況下,當(dāng)前解析的開(kāi)始標(biāo)簽是否是禁止在模板中使用的標(biāo)簽。哪些是禁止的呢?
isForbiddenTag 函數(shù)
function isForbiddenTag(el) { return ( el.tag === 'style' || (el.tag === 'script' && ( !el.attrsMap.type || el.attrsMap.type === 'text/javascript' )) ) }
可以看到,style,script 都是在禁止名單中,但通過(guò)isForbiddenTag 也發(fā)現(xiàn)一個(gè)彩蛋。
<script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script>
當(dāng)定義模板的方式如上,在 <script> 元素上添加 type="text/x-template" 屬性。 此時(shí)的script不會(huì)被禁止。
最后還會(huì)在當(dāng)前元素的描述對(duì)象上添加 element.forbidden 屬性,并將其值設(shè)置為true。
接下來(lái)源碼:
for (var i = 0; i < preTransforms.length; i++) { element = preTransforms[i](element, options) || element; }
如上代碼中使用 for 循環(huán)遍歷了preTransforms 數(shù)組,preTransforms 是通過(guò)pluckModuleFunction 函數(shù)從options.modules 選項(xiàng)中篩選出名字為preTransformNode 函數(shù)所組成的數(shù)組。實(shí)際上 preTransforms 數(shù)組中只有一個(gè) preTransformNode 函數(shù)該函數(shù)只用來(lái)處理 input 標(biāo)簽我們?cè)诤竺嬲鹿?jié)會(huì)來(lái)講它。
接下來(lái)源碼:
if (!inVPre) { processPre(element); if (element.pre) { inVPre = true; } } if (platformIsPreTag(element.tag)) { inPre = true; } if (inVPre) { processRawAttrs(element); } else if (!element.processed) { // structural directives processFor(element); processIf(element); processOnce(element); // element-scope stuff processElement(element, options); }
可以看到這里會(huì)有大量的process*的函數(shù),這些函數(shù)是做什么用的呢?實(shí)際上process* 系列函數(shù)的作用就是對(duì)元素描述對(duì)象做進(jìn)一步處理,比如其中一個(gè)函數(shù)叫做 processPre,這個(gè)函數(shù)的作用就是用來(lái)檢測(cè)元素是否擁有v-pre 屬性,如果有v-pre 屬性則會(huì)在 element 描述對(duì)象上添加一個(gè) pre 屬性,如下:
{ type: 1, tag, attrsList: attrs, attrsMap: makeAttrsMap(attrs), parent, children: [], pre: true }
總結(jié):所有process* 系列函數(shù)的作用都是為了讓一個(gè)元素的描述對(duì)象更加充實(shí),使這個(gè)對(duì)象能更加詳細(xì)地描述一個(gè)元素, 不過(guò)我們本節(jié)主要總結(jié)解析一個(gè)開(kāi)始標(biāo)簽需要做的事情,所以稍后去看這些代碼的實(shí)現(xiàn)。
接下來(lái)源碼:
function checkRootConstraints(el) { { if (el.tag === 'slot' || el.tag === 'template') { warnOnce( "Cannot use <" + (el.tag) + "> as component root element because it may " + 'contain multiple nodes.' ); } if (el.attrsMap.hasOwnProperty('v-for')) { warnOnce( 'Cannot use v-for on stateful component root element because ' + 'it renders multiple elements.' ); } } }
我們知道在編寫(xiě) Vue 模板的時(shí)候會(huì)受到兩種約束,首先模板必須有且僅有一個(gè)被渲染的根元素,第二不能使用 slot 標(biāo)簽和 template 標(biāo)簽作為模板的根元素。
checkRootConstraints 函數(shù)內(nèi)部首先通過(guò)判斷 el.tag === 'slot' || el.tag === 'template' 來(lái)判斷根元素是否是slot 標(biāo)簽或 template 標(biāo)簽,如果是則打印警告信息。接著又判斷當(dāng)前元素是否使用了 v-for 指令,因?yàn)関-for 指令會(huì)渲染多個(gè)節(jié)點(diǎn)所以根元素是不允許使用 v-for 指令的。
接下來(lái)源碼:
if (!root) { root = element; checkRootConstraints(root); } else if (!stack.length) { // allow root elements with v-if, v-else-if and v-else if (root.if && (element.elseif || element.else)) { checkRootConstraints(element); addIfCondition(root, { exp: element.elseif, block: element }); } else { warnOnce( "Component template should contain exactly one root element. " + "If you are using v-if on multiple elements, " + "use v-else-if to chain them instead." ); } }
這個(gè) if 語(yǔ)句先檢測(cè) root 是否存在!我們知道 root 變量在一開(kāi)始是不存在的,如果 root 不存在那說(shuō)明當(dāng)前元素應(yīng)該就是根元素,所以在 if 語(yǔ)句塊內(nèi)直接把當(dāng)前元素的描述對(duì)象 element 賦值給 root 變量,同時(shí)會(huì)調(diào)用 checkRootConstraints函數(shù)檢查根元素是否符合要求。
再來(lái)看 else if 語(yǔ)句的條件,當(dāng) stack 為空的情況下會(huì)執(zhí)行 else if 語(yǔ)句塊內(nèi)的代碼, 那stack 什么情況下才為空呢?前面已經(jīng)多次提到每當(dāng)遇到一個(gè)非一元標(biāo)簽時(shí)就會(huì)將該標(biāo)簽的描述對(duì)象放進(jìn)數(shù)組,并且每當(dāng)遇到一個(gè)結(jié)束標(biāo)簽時(shí)都會(huì)將該標(biāo)簽的描述對(duì)象從 stack 數(shù)組中拿掉,那也就是說(shuō)在只有一個(gè)根元素的情況下,正常解析完成一段 html 代碼后 stack 數(shù)組應(yīng)該為空,或者換個(gè)說(shuō)法,即當(dāng) stack 數(shù)組被清空后則說(shuō)明整個(gè)模板字符串已經(jīng)解析完畢了,但此時(shí) start 鉤子函數(shù)仍然被調(diào)用了,這說(shuō)明模板中存在多個(gè)根元素,這時(shí) else if 語(yǔ)句塊內(nèi)的代碼將被執(zhí)行:
接下來(lái)源碼:
if (root.if && (element.elseif || element.else)) { checkRootConstraints(element); addIfCondition(root, { exp: element.elseif, block: element }); } else { warnOnce( "Component template should contain exactly one root element. " + "If you are using v-if on multiple elements, " + "use v-else-if to chain them instead." ); }
想要能看懂這個(gè)代碼,你需要懂一些前置知識(shí)。
[ Vue條件渲染 ] (https://cn.vuejs.org/v2/guide/conditional.html)
我們知道在編寫(xiě) Vue 模板時(shí)的約束是必須有且僅有一個(gè)被渲染的根元素,但你可以定義多個(gè)根元素,只要能夠保證最終只渲染其中一個(gè)元素即可,能夠達(dá)到這個(gè)目的的方式只有一種,那就是在多個(gè)根元素之間使用 v-if 或 v-else-if 或 v-else 。
示例代碼:
<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div>
在回歸到代碼部分。
if (root.if && (element.elseif || element.else))
root 對(duì)象中的 .if 屬性、.elseif 屬性以及 .else 屬性都是哪里來(lái)的,它們是在通過(guò) processIf 函數(shù)處理元素描述對(duì)象時(shí),如果發(fā)現(xiàn)元素的屬性中有 v-if 或 v-else-if 或 v-else ,則會(huì)在元素描述對(duì)象上添加相應(yīng)的屬性作為標(biāo)識(shí)。
上面代碼如果第一個(gè)根元素上有 .if 的屬性,而非第一個(gè)根元素 element 有 .elseif 屬性或者 .else 屬性,這說(shuō)明根元素都是由 v-if、v-else-if、v-else 指令控制的,同時(shí)也保證了被渲染的根元素只有一個(gè)。
接下來(lái)繼續(xù)看:
if (root.if && (element.elseif || element.else)) { checkRootConstraints(element); addIfCondition(root, { exp: element.elseif, block: element }); } else { warnOnce( "Component template should contain exactly one root element. " + "If you are using v-if on multiple elements, " + "use v-else-if to chain them instead." ); }
checkRootConstraints 函數(shù)檢查當(dāng)前元素是否符合作為根元素的要求,這都能理解。
addIfCondition是什么
看下它的源代碼。
function addIfCondition(el, condition) { if (!el.ifConditions) { el.ifConditions = []; } el.ifConditions.push(condition); }
代碼很簡(jiǎn)單,調(diào)用addIfCondition 傳遞的參數(shù) root 對(duì)象,在函數(shù)體中擴(kuò)展一個(gè)屬性addIfCondition, root.addIfCondition 屬性值是一個(gè)對(duì)象。 此對(duì)象中有兩個(gè)屬性exp、block。實(shí)際上該函數(shù)是一個(gè)通用的函數(shù),不僅僅用在根元素中,它用在任何由 v-if、v-else-if 以及 v-else 組成的條件渲染的模板中。
通過(guò)如上分析我們可以發(fā)現(xiàn),具有 v-else-if 或 v-else 屬性的元素的描述對(duì)象會(huì)被添加到具有 v-if 屬性的元素描述對(duì)象的 .ifConnditions 數(shù)組中。
舉個(gè)例子,如下模板:
<div v-if="A"></div> <div v-else-if="B"></div> <div v-else-if="C"></div> <div v-else></div>
解析后生成的 AST 如下(簡(jiǎn)化版):
{ type: 1, tag: 'div', ifConditions: [ { exp: 'A', block: { type: 1, tag: 'div' /* 省略其他屬性 */ } }, { exp: 'B', block: { type: 1, tag: 'div' /* 省略其他屬性 */ } }, { exp: 'C', block: { type: 1, tag: 'div' /* 省略其他屬性 */ } }, { exp: 'undefined', block: { type: 1, tag: 'div' /* 省略其他屬性 */ } } ] // 省略其他屬性... }
假如當(dāng)前元素不滿足條件:root.if && (element.elseif || element.else) ,那么在非生產(chǎn)環(huán)境下會(huì)打印了警告信息。
接下來(lái)源碼:
if (currentParent && !element.forbidden) { if (element.elseif || element.else) { processIfConditions(element, currentParent); } else if (element.slotScope) { // scoped slot currentParent.plain = false; var name = element.slotTarget || '"default"'; (currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element; } else { currentParent.children.push(element); element.parent = currentParent; } } if (!unary) { currentParent = element; stack.push(element); } else { closeElement(element); }
我們先從下往上講, 為什么呢?原因是在解析根元素的時(shí)候currentParent并沒(méi)有賦值。
!unary 表示解析的是非一元標(biāo)簽,此時(shí)把該元素的描述對(duì)象添加到stack 棧中,并且將 currentParent 變量的值更新為當(dāng)前元素的描述對(duì)象。如果一個(gè)元素是一元標(biāo)簽,那么應(yīng)該調(diào)用 closeElement 函數(shù)閉合該元素。
老生常談的總結(jié):每當(dāng)遇到一個(gè)非一元標(biāo)簽都會(huì)將該元素的描述對(duì)象添加到stack數(shù)組,并且currentParent 始終存儲(chǔ)的是 stack 棧頂?shù)脑?,即?dāng)前解析元素的父級(jí)。
if (currentParent && !element.forbidden) { if (element.elseif || element.else) { processIfConditions(element, currentParent); } else if (element.slotScope) { // scoped slot currentParent.plain = false; var name = element.slotTarget || '"default"'; (currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element; } else { currentParent.children.push(element); element.parent = currentParent; } }
這里的條件要成立,則說(shuō)明當(dāng)前元素存在父級(jí)( currentParent ),并且當(dāng)前元素不是被禁止的元素。
常見(jiàn)的情況如下:
if (currentParent && !element.forbidden) { if (element.elseif || element.else) { //... } else if (element.slotScope) { // scoped slot //... } else { currentParent.children.push(element); element.parent = currentParent; } }
在 else 語(yǔ)句塊內(nèi),會(huì)把當(dāng)前元素描述對(duì)象添加到父級(jí)元素描述對(duì)象 ( currentParent ) 的children 數(shù)組中,同時(shí)將當(dāng)前元素對(duì)象的 parent 屬性指向父級(jí)元素對(duì)象,這樣就建立了元素描述對(duì)象間的父子級(jí)關(guān)系。
如果一個(gè)標(biāo)簽使用 v-else-if 或 v-else 指令,那么該元素的描述對(duì)象實(shí)際上會(huì)被添加到對(duì)應(yīng)的v-if 元素描述對(duì)象的 ifConditions 數(shù)組中,而非作為一個(gè)獨(dú)立的子節(jié)點(diǎn),這個(gè)工作就是由如下代碼完成:
if (currentParent && !element.forbidden) { if (element.elseif || element.else) { processIfConditions(element, currentParent); } else if (element.slotScope) { // scoped slot currentParent.plain = false; var name = element.slotTarget || '"default"'; (currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element; } else { //... } }
如當(dāng)前解析的元素使用了 v-else-if 或 v-else 指令,則會(huì)調(diào)用 processIfConditions 函數(shù),同時(shí)將當(dāng)前元素描述對(duì)象 element 和父級(jí)元素的描述對(duì)象 currentParent 作為參數(shù)傳遞:
processIfConditions 源碼
function processIfConditions(el, parent) { var prev = findPrevElement(parent.children); if (prev && prev.if) { addIfCondition(prev, { exp: el.elseif, block: el }); } else { warn$2( "v-" + (el.elseif ? ('else-if="' + el.elseif + '"') : 'else') + " " + "used on element <" + (el.tag) + "> without corresponding v-if." ); } }
findPrevElement 函數(shù)是去查找到當(dāng)前元素的前一個(gè)元素描述對(duì)象,并將其賦值給 prev 常量,addIfCondition 不用多說(shuō)如果prev 、prev.if 存在,調(diào)用 addIfCondition 函數(shù)在當(dāng)前元素描述對(duì)象添加 ifConditions 屬性,傳入的對(duì)象存儲(chǔ)相關(guān)信息。
如果當(dāng)前元素沒(méi)有使用 v-else-if 或 v-else 指令,那么還會(huì)判斷當(dāng)前元素是否使用了 slot-scope 特性,如下:
if (currentParent && !element.forbidden) { if (element.elseif || element.else) { //... } else if (element.slotScope) { // scoped slot currentParent.plain = false; var name = element.slotTarget || '"default"'; (currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element; } else { //... } }
如果一個(gè)元素使用了 slot-scope 特性,那么該元素的描述對(duì)象會(huì)被添加到父級(jí)元素的scopedSlots 對(duì)象下,也就是說(shuō)使用了 slot-scope 特性的元素與使用了v-else-if 或 v-else 指令的元素一樣,他們都不會(huì)作為父級(jí)元素的子節(jié)點(diǎn),對(duì)于使用了 slot-scope 特性的元素來(lái)講它們將被添加到父級(jí)元素描述對(duì)象的 scopedSlots 對(duì)象下。
自 2.6.0 起有所更新。已廢棄的使用slot-scope 特性的語(yǔ)法在這里。所以此塊內(nèi)容就不鋪開(kāi)來(lái)講了,有興趣的同學(xué)可以去了解下,更多關(guān)于vue parseHTML start鉤子函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
玩轉(zhuǎn)vue的slot內(nèi)容分發(fā)
這篇文章主要介紹了玩轉(zhuǎn)vue的slot內(nèi)容分發(fā),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09Vue-router路由判斷頁(yè)面未登錄跳轉(zhuǎn)到登錄頁(yè)面的實(shí)例
下面小編就為大家?guī)?lái)一篇Vue-router路由判斷頁(yè)面未登錄跳轉(zhuǎn)到登錄頁(yè)面的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10vue如何監(jiān)聽(tīng)頁(yè)面的滾動(dòng)的開(kāi)始和結(jié)束
這篇文章主要介紹了vue如何監(jiān)聽(tīng)頁(yè)面的滾動(dòng)的開(kāi)始和結(jié)束,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07vue實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀑布流 + 下拉刷新 + 上拉加載更多(步驟詳解)
這篇文章主要介紹了vue實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀑布流 + 下拉刷新 + 上拉加載更多,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01vue2手機(jī)APP項(xiàng)目添加開(kāi)屏廣告或者閃屏廣告
這篇文章主要為大家詳細(xì)介紹了vue2手機(jī)APP項(xiàng)目添加開(kāi)屏廣告或者閃屏廣告的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11vue中使用file-saver導(dǎo)出文件的全過(guò)程記錄
這篇文章主要給大家介紹了關(guān)于vue中使用file-saver導(dǎo)出文件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02el-input無(wú)法輸入的問(wèn)題和表單驗(yàn)證失敗問(wèn)題解決
在做項(xiàng)目的時(shí)候發(fā)現(xiàn)一個(gè)情況,輸入框無(wú)法輸入值并且表單校驗(yàn)失靈,所以下面這篇文章主要給大家介紹了關(guān)于el-input無(wú)法輸入的問(wèn)題和表單驗(yàn)證失敗問(wèn)題解決的相關(guān)資料,需要的朋友可以參考下2023-02-02vscode中eslint插件的配置(prettier配置無(wú)效)
這篇文章主要介紹了vscode中eslint插件的配置(prettier配置無(wú)效),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09修改el-form-item中的label里面的字體邊距或者大小問(wèn)題
這篇文章主要介紹了修改el-form-item中的label里面的字體邊距或者大小問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10