Vue入门实战教程(三)—— 视图层:模板及指令

 

此学习教程是对官方教程的解析,

本章节主要涉及到的官方教程地址:

模板语法—— 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入门实战教程 | 寒于水学习网

下一章:Vue入门实战教程(四)—— 模型层:数据

特定模板语法实战:

Vue特定模板语法实战(一):Class和Style绑定

Vue特定模板语法实战(二):条件渲染

Vue特定模板语法实战(三):列表渲染

Vue特定模板语法实战(四):事件处理

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值