此学习教程是对官方教程的解析,
本章节主要涉及到的官方教程地址:
模板语法—— Vue.js,自定义指令——Vue.js, 异步组件——Vue.js
上一章 :Vue入门实战教程(二)——Vue介绍
三. 视图层:模板及指令
1. 模板语法
官方教程:
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
模板语法: 基于 HTML, 将DOM和Vue 实例的数据绑定(声明式)。
1.1 绑定插值
1.1.1 响应式绑定
(1)普通文本
“Mustache”语法 (双大括号)
(1.1)单个数据
{{ number}}
(1.2)表达式:只能包含单个表达式,完全的 JavaScript 表达式支持
(1.2.1)基本算术运算:{{ number + 1 }}
(1.2.2)字符串拼接: <div v-bind:id="'list-' + id"></div>
(1.2.3)二元表达式: {{ ok ? 'YES' : 'NO' }}
(1.2.4)调用方法:{{ message.split('').reverse().join('') }}
(1.3)调用实例方法:具体在方法、过滤器章节讲解,先有个印象
<p>{{ reversedMessage(message) }}</p>
(1.4)使用过滤器:具体在方法、过滤器章节讲解,先有个印象
<p>{{ message | reversedMessage }}</p>
(2)HTML内容
v-html:输出真正的 HTML
<span v-html="rawHtml"></span>
1.1.2 一次性绑定
v-once指令:执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定
<span v-once>这个将不会改变: {{ msg }}</span>
1.2 绑定属性
v-bind指令,缩写是一个冒号(:)
1.3 绑定DOM结构
v-if、v-for指令
1.4 绑定事件
v-on指令,缩写是@
1.5 绑定用户输入
v-model
2. 指令
官方教程:
指令 (Directives) : 是带有 v-
前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for
是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
2.1 指令类型
2.1.1 无参数指令
v-if, v-once, v-html,v-for
2.1.2 固定参数指令
v-bind:href,缩写 :href
v-on:click,缩写 @click
2.1.3 动态参数指令
v-bind:[动态参数],缩写 :[动态参数]
v-on:[动态参数],缩写 @[动态参数]
动态参数约束
1.预期会求出一个字符串
2.无法使用空格和引号
3.在 DOM 中使用模板时 (直接在一个 HTML 文件里撰写模板),还需要避免使用大写字符来命名
2.2 修饰符:以特殊方式绑定指令
修饰符 (modifier) 是以半角句号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
v-on:submit.prevent: .prevent
修饰符告诉 v-on
指令对于触发的事件调用 event.preventDefault()
2.3 自定义指令
除了核心功能默认内置的指令 (例如:v-model
、v-show
),Vue 也允许注册自定义指令。
具体注册自定义指令的选项请参考官方教程。
全局注册自定义指令:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="vm">
<input v-focus>
</div>
<script>
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
var vm = new Vue({
el: '#vm'
})
</script>
</body>
</html>
局部注册自定义指令:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="vm">
<input v-focus>
</div>
<script>
var vm = new Vue({
el: '#vm',
//指令资源
directives: {
//局部注册
focus: {
inserted: function (el) {
el.focus()
}
}
}
})
</script>
</body>
</html>
3. 模板使用
3.1 模板挂载
官方教程:
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
如果你熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,你也可以不用模板,直接写渲染 (render) 函数,使用可选的 JSX 语法。
理解两个概念:
模板:最终编译成虚拟 DOM 渲染(render)函数的HTML字符串
编译:将一个模板字符串转成 虚拟DOM 渲染(render)函数的处理过程。
3.1.1 自动编译并挂载: el选项
参考API说明: el选项
API说明解析:
el选项: 在且仅在创建实例时,指定的一个DOM元素,作为Vue生成的DOM(由虚拟DOM 渲染函数所生成)的挂载目标。
(1) 在且仅在创建实例时:el选项只有用 new
创建实例时生效。所以Vue实例创建后再为vm.$el赋值是不起作用的。
(2) 指定的一个DOM元素:使用CSS 选择器或 HTMLElement 实例指定,注意只能指定一个DOM元素。如果使用CSS 选择器选择了多个元素,Vue只会选择第一个元素(可以实践下)。
(3) 作为挂载目标: 本质上就是作为替换目标, 意思是将这个指定的DOM元素用Vue生成的DOM来替换。
(4) Vue生成的DOM(由虚拟DOM 渲染函数所生成):Vue生成的DOM是由虚拟DOM 渲染函数所生成的,所以如果有模板的话,则必须首先将模板编译成虚拟DOM 渲染函数。也就是挂载的前提是编译。
(4.1)模板:由 Vue实例的render
函数和 template
属性指定,如果同时存在,忽略template属性;
如果 render
函数和 template
属性都不存在,则由el选项指定的挂载 DOM 元素的 HTML 会被提取出来用作模板;如果el、template、render
都不存在,则没有模板。
(4.2)何时编译:如果在Vue实例的实例化时存在el选项,实例将立即进入编译过程,否则,需要显式调用 vm.$mount()
手动开启编译。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
<div>{{ hi }}</div>
</div>
<script>
var vue_app = new Vue({
//使用CSS选择器
el:"#mountElement",
//使用HTMLElement 实例
//el:document.getElementById("mountElement"),
data: {
hi: 'abc'
}
})
</script>
</body>
</html>
运行结果:
查看vm.$el的值:
可以看到无论最终HTML还是挂载元素vm.$el的HTML内容,最终渲染结果的都是:
<div id="mountElement">
<div>abc</div>
</div>
3.1.2 使用template选项
使用template实现上面同样的渲染结果:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
</div>
<script>
var vm= new Vue({
el: "#mountElement",
template:"<div id='mountElement'><div>{{ hi }}</div></div>",
data: {
hi: 'abc'
}
})
</script>
</body>
</html>
运行后,无论最终HTML还是vm.$el元素的HTML内容,都和上例是一样的。
下面例子实现了同样的HTML渲染,但是挂载元素vm.$el不一样了:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
</div>
<script>
var vm= new Vue({
template:"<div>{{ hi }}</div>",
data: {
hi: 'abc'
}
})
vm.$mount()
document.getElementById('mountElement').appendChild(vm.$el)
</script>
</body>
</html>
也可以写成这样:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
</div>
<script type="x-template" id="templateDiv">
<div>{{ hi }}</div>
</script>
<script>
var vm = new Vue({
template:"#templateDiv",
data: {
hi: 'abc'
}
})
vm.$mount()
document.getElementById('mountElement').appendChild(vm.$el)
</script>
</body>
</html>
运行结果:
查看vm.$el:
vm.$el挂载元素内容变成了:
<div>abc</div>
以下示例最终渲染结果和vm.$el都改变了:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
</div>
<script type="x-template" id="templateDiv">
<div>{{ hi }}</div>
</script>
<script>
var vm = new Vue({
el:"#mountElement",
template:"#templateDiv",
data: {
hi: 'abc'
}
})
</script>
</body>
</html>
也可以这么写
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
</div>
<script type="x-template" id="templateDiv">
<div>{{ hi }}</div>
</script>
<script>
var vm = new Vue({
template:"#templateDiv",
data: {
hi: 'abc'
}
})
vm.$mount("#mountElement");
</script>
</body>
</html>
运行结果:
vm.$el:
可以看到无论最终HTML还是挂载元素vm.$el的HTML内容,最终渲染结果的都是:
<div>abc</div>
3.1.3 使用DOM渲染函数render: 先有个印象,后面的章节详解
下例使用DOM渲染函数实现上例相同的结果:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="mountElement">
</div>
<script>
var vm= new Vue({
render: function(createElement) {
return createElement('div', this.hi);
},
data: {
hi: 'abc'
}
})
//第一种挂载方式,替换挂载元素
vm.$mount('#mountElement')
//第二种挂载方式,不替换挂载元素
//vue_app.$mount()
//document.getElementById('mountElement').appendChild(vm.$el)
</script>
</body>
</html>
3.2 模板和Vue实例不在同一个文件中
既然视图和数据是解耦的,那作为视图的模板能否独立出来呢?当然可以,现在介绍三种基础的简单实现方法。更高级的用法以后在介绍。
首先,将模板独立在一个template.html文件:
<div>{{ hi }}</div>
因JS无法直接访问本地文件,所以下面例子需将html部署到WEB服务器中运行:
3.2.1 使用iframe
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<iframe id="templateFrame" src="template.html" width="0" height="0" frameborder="0"></iframe>
<div id="templateDiv"></div>
<script>
var templateFrame = document.getElementById("templateFrame");
templateFrame.onload = function() {
document.getElementById("templateDiv").innerHTML = templateFrame.contentWindow.document.body.innerHTML;
var vm = new Vue({
el: "#templateDiv",
data: {
hi: 'abc'
}
});
}
</script>
</body>
</html>
3.2.2 使用ajax
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
</head>
<body>
<div id="templateDiv"></div>
<script>
axios.get('template.html').then(function (response) {
document.getElementById("templateDiv").innerHTML = response.data;
var vm = new Vue({
el:"#templateDiv",
data: {
hi: 'abc'
}
});
})
.catch(function (error) {
console.log('加载失败!');
})
</script>
</body>
</html>
3.2.3 使用异步组件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
</head>
<body>
<div id="templateDiv">
<hi-div hi="abc"></hi-div>
</div>
<script>
Vue.component('hi-div', function (resolve, reject) {
axios.get('template.html').then(function (response) {
resolve({
template: response.data,
props: ['hi']
})
});
});
var vm = new Vue({
el:"#templateDiv"
});
</script>
</body>
</html>
本章节教程结束。
全部教程地址:Vue入门实战教程 | 寒于水学习网
特定模板语法实战: