getSlotName、processSlotOutlet、processComponent
文件位置:/src/compiler/parser/index.js
getSlotName
/** * 解析 binding,得到插槽名称以及是否为动态插槽 * @returns { name: 插槽名称, dynamic: 是否为动态插槽 } */ function getSlotName (binding) { let name = binding.name.replace(slotRE, '') if (!name) { if (binding.name[0] !== '#') { name = 'default' } else if (process.env.NODE_ENV !== 'production') { warn( `v-slot shorthand syntax requires a slot name.`, binding ) } } return dynamicArgRE.test(name) // dynamic [name] ? { name: name.slice(1, -1), dynamic: true } // static name : { name: `"${name}"`, dynamic: false } } 复制代码
processSlotOutlet
// handle <slot/> outlets,处理自闭合 slot 标签 // 得到插槽名称,el.slotName function processSlotOutlet (el) { if (el.tag === 'slot') { // 得到插槽名称 el.slotName = getBindingAttr(el, 'name') // 不允许在 slot 标签上使用 key 属性 if (process.env.NODE_ENV !== 'production' && el.key) { warn( `\`key\` does not work on <slot> because slots are abstract outlets ` + `and can possibly expand into multiple elements. ` + `Use the key on a wrapping element instead.`, getRawBindingAttr(el, 'key') ) } } } 复制代码
processComponent
/** * 处理动态组件,<component :is="compName"></component> * 得到 el.component = compName */ function processComponent (el) { let binding // 解析 is 属性,得到属性值,即组件名称,el.component = compName if ((binding = getBindingAttr(el, 'is'))) { el.component = binding } /* <component :is="compName" inline-template>xx</component> 组件上存在 inline-template 属性,进行标记:el.inlineTemplate = true 表示组件开始和结束标签内的内容作为组件模版出现,而不是作为插槽别分发,方便定义组件模版 */ if (getAndRemoveAttr(el, 'inline-template') != null) { el.inlineTemplate = true } } 复制代码
transformNode() —— class 模块
文件位置:/src/platforms/web/compiler/modules/class.js
/** * 处理元素上的 class 属性 * 静态的 class 属性值赋值给 el.staticClass 属性 * 动态的 class 属性值赋值给 el.classBinding 属性 */ function transformNode (el: ASTElement, options: CompilerOptions) { const warn = options.warn || baseWarn // 获取元素上静态 class 属性的值 xx,<div class="xx"></div> const staticClass = getAndRemoveAttr(el, 'class') if (process.env.NODE_ENV !== 'production' && staticClass) { const res = parseText(staticClass, options.delimiters) // 警告提示,同 style 的提示一样,不能使用 <div class="{{ val}}"></div>,请用 // <div :class="val"></div> 代替 if (res) { warn( `class="${staticClass}": ` + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div class="{{ val }}">, use <div :class="val">.', el.rawAttrsMap['class'] ) } } // 静态 class 属性值赋值给 el.staticClass if (staticClass) { el.staticClass = JSON.stringify(staticClass.replace(/\s+/g, ' ').trim()) } // 获取动态绑定的 class 属性值,并赋值给 el.classBinding const classBinding = getBindingAttr(el, 'class', false /* getStatic */) if (classBinding) { el.classBinding = classBinding } } 复制代码
transformNode() —— style 模块
文件位置:/src/platforms/web/compiler/modules/style.js
/** * 从 el 上解析出静态的 style 属性和动态绑定的 style 属性,分别赋值给: * el.staticStyle 和 el.styleBinding */ function transformNode (el: ASTElement, options: CompilerOptions) { const warn = options.warn || baseWarn // <div style="xx"></div> // 获取 style 属性 const staticStyle = getAndRemoveAttr(el, 'style') if (staticStyle) { /* istanbul ignore if 提示,如果从 xx 中解析到了界定符,说明是一个动态的 style, 比如 <div style="{{ val }}"></div>则给出提示: 动态的 style 请使用 <div :style="val"></div> */ if (process.env.NODE_ENV !== 'production') { const res = parseText(staticStyle, options.delimiters) if (res) { warn( `style="${staticStyle}": ` + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div style="{{ val }}">, use <div :style="val">.', el.rawAttrsMap['style'] ) } } // 将静态的 style 样式赋值给 el.staticStyle el.staticStyle = JSON.stringify(parseStyleText(staticStyle)) } // 获取动态绑定的 style 属性,比如 <div :style="styleVariable"></div> const styleBinding = getBindingAttr(el, 'style', false /* getStatic */) if (styleBinding) { // 赋值给 el.styleBinding el.styleBinding = styleBinding } }