Vue中template的几种写法(含源码分析)

913 阅读2分钟

template有以下几种写法:

第一种方式:模板字符串直接书写

	<div id="app"></div>
	const vm = new Vue({
		el: '#app',
		template:`<div>姓名:{{ name }}<div>`,
		data: {
			name: 'ludeng',
		}
	});

这种方式如果代码量很大,书写非常困难也很不美观。(示例用了ES6模板字符串,有耐心的话也可以用字符串拼接)

第二种方式:使用template元素

这种方式是把template的内容单独提出来放到<template />元素中

	<div id="app"></div>
	
	<template id="tmp">
		<div>
			姓名: {{ name }}
		</div>
	</template>
	const vm = new Vue({
		el: '#app',
		template:'#tmp',
		data: {
			name: 'ludeng',
		}
	});

template值还可以直接是DOM元素template: document.querySelector('#tmp'),效果相同。最后都是取template元素的innerHTML作为编译模板

多说一嘴,template元素是H5标准,在此之前是用script标签实现的模板元素功能,写法如下:

	<div id="app"></div>
	
	<script type="x-template" id="tmp">
		<div>
			姓名: {{ name }}
		</div>
	</script>

效果一样,都是把template的内容提取出来

第三种方式:不写template

直接在el元素里书写模板代码,这种方式是最常用的方式。

	<div id="app">
		<div>
			姓名: {{ name }}
		</div>
	</div>
	const vm = new Vue({
		el: '#app',
		data: {
			name: 'ludeng',
		}
	});

这种方式把el的outerHTML作为template进行编译

最后,从源码角度理解template几种方式的实现:

template源码分析

源码路径:platforms/web/entry-runtime-with-compiler.js github.com/vuejs/vue/b…

Vue.prototype.$mount函数中找到以下代码:

	let template = this.$options.template	//取template值
	if (template) {	//设置了template
	  if (typeof template === 'string') {	//template为模板字符串或者 '#tmp'形式
	    if (template.charAt(0) === '#') {	//template:'#tmp'形式
	      template = idToTemplate(template)	// document.querySelector('#tmp').innerHTML
	    }
	  } else if (template.nodeType) { //document.querySelector('#tmp')形式
	    template = template.innerHTML
	  } else {	// template选项无效
	    return this
	  }
	} else if (el) {	//如果没定义template 则把el的outerHTML作为模板
	  template = getOuterHTML(el)
	}
	......
	compileToFunctions(template) //将template编译为render function

template:'#tmp'形式,调用idToTemplate

idToTemplate:

根据id返回元素的innerHTML作为template

	const idToTemplate = cached(id => { 
	  const el = query(id)
	  return el && el.innerHTML
	})

vue会进行缓存,有缓存则读缓存结果,没有缓存则运行回调函数

下面是cached源码: (shared/util.js)

	export function cached(fn){
	  const cache = Object.create(null)
	  return (function cachedFn (str) {
	    const hit = cache[str]
	    return hit || (cache[str] = fn(str))	//有缓存读缓存,没缓存则运行回调函数
	  })
	}

如果未设置template,则调用getOuterHTML获得el的outerHTML

getOuterHTML:

	function getOuterHTML (el){
	  if (el.outerHTML) {
	    return el.outerHTML
	  } else {	// 解决firefox没有outerHTML的问题
	    const container = document.createElement('div')
	    container.appendChild(el.cloneNode(true))
	    return container.innerHTML
	  }
	}

总结:

  • template编译主要有两种情况:

    1. 如果设置了template,将template编译成render function
    2. 否则将el的outerHTML作为template进行编译
  • template四种写法:

  1. template: `<div>姓名:{{ name }}</div>`
  2. template:'#tmp',
  3. template: document.querySelector('#tmp'),
  4. 不写template