高频面试题:
vue
中的v-slot
?
答案:v-shot
产生的主要目的是,在组件的使用过程中可以让父组件有修改子组件内容的能力,就像在子组件里面放了个插槽,让父组件往插槽内塞入父组件中的楔子;并且,父组件在子组件中嵌入的楔子也可以访问子组件中的数据。v-slot
的产生让组件的应用更加灵活。
一、具名插槽
// 在main.js文件中
let baseLayout = {template: `<div class="container"><header><slot name="header"></slot></header><main><slot></slot></main><footer><slot name="footer"></slot></footer></div>`,data() {return {url: ""};}
};
new Vue({el: "#app",template: `<base-layout><template v-slot:header><h1>title-txt</h1></template><p>paragraph-1-txt</p><p>paragraph-2-txt</p><template v-slot:footer><p>foot-txt</p></template></base-layout>`,components: {baseLayout}
});
当前例子渲染成真实的页面需要经历编译,虚拟DOM的获取和渲染过程。
1、编译部分
(1)ast
在ast
的创建过程中,当执行到闭合标签时,会进行闭合标签的属性处理closeElement(element)
:
function closeElement (element) {trimEndingWhitespace(element)if (!inVPre && !element.processed) {element = processElement(element, options)}// tree managementif (!stack.length && element !== root) {// allow root elements with v-if, v-else-if and v-elseif (root.if && (element.elseif || element.else)) {if (process.env.NODE_ENV !== 'production') {checkRootConstraints(element)}addIfCondition(root, {exp: element.elseif,block: element})} else if (process.env.NODE_ENV !== 'production') {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.`,{ start: element.start })}}if (currentParent && !element.forbidden) {if (element.elseif || element.else) {processIfConditions(element, currentParent)} else {if (element.slotScope) {// scoped slot// keep it in the children list so that v-else(-if) conditions can// find it as the prev node.const name = element.slotTarget || '"default"';(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element}currentParent.children.push(element)element.parent = currentParent}}// final children cleanup// filter out scoped slotselement.children = element.children.filter(c => !(c: any).slotScope)// remove trailing whitespace node againtrimEndingWhitespace(element)// check pre stateif (element.pre) {inVPre = false}if (platformIsPreTag(element.tag)) {inPre = false}// apply post-transformsfor (let i = 0; i < postTransforms.length; i++) {postTransforms[i](element, options)}}
其中的 element = processElement(element, options)
逻辑中会执行到slot
相关的处理逻辑,这里主要看版本号大于2.6+
的情况:
// 2.6 v-slot syntax
if (el.tag === 'template') {// v-slot on <template>const slotBinding = getAndRemoveAttrByRegex(el, slotRE)if (slotBinding) {if (process.env.NODE_ENV !== 'production') {if (el.slotTarget || el.slotScope) {warn(`Unexpected mixed usage of different slot syntaxes.`,el)}if (el.parent && !maybeComponent(el.parent)) {warn(`<template v-slot> can only appear at the root level inside ` +`the receiving component`,el)}}const { name, d