模板语法
在React使用的jsx,所以对应的代码都是编写的类似于将JS嵌入到HTML中的一种语法,之后需要通过Babel将jsx编译成 React.createElement 函数调用。
Vue也支持jsx的开发模式,但是大多数情况下,使用基于HTML的模板语法。
在模板中,允许开发者以声明式的方式将DOM和底层组件实例的数据绑定在一起(mustache语法在模板中绑定对应data)
在底层的实现中,Vue会将模板编译成虚拟DOM,随后使用render函数进行界面渲染
Mustache语法
如果我们希望把数据显示到模板(template)中,使用最多的语法是 “Mustache”语法 (双大括号) 的文本插值
data返回的对象是有添加到Vue的响应式系统中,因此当data中的数据发生改变时,对应的内容也会自动发生更新。
<!-- 1. 基本使用 -->
<h2>{{ msg }}</h2>
<!-- 2. 可以同时使用多个mustache -->
<h2>{{ msg }} --- {{ msg }}</h2>
<!-- 3. mustache中可以使用任何合法的js表达式 -->
<h2>{{ msg.toUpperCase() }}</h2>
<h2>{{ isLogin ? 'Login Out': 'Login In' }}</h2>
<!-- 4. 可以在mustache中调用函数和使用计算属性 -->
<h2>{{ reverseMsg }}</h2>
<h2>{{ getReverseMsg() }}</h2>
常见指令
v-once
v-once用于指定元素或者组件只渲染一次
当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过
该指令可以用于性能优化
<!-- count值不会发生改变 -->
<h2 v-once>{{ count }}</h2>
<!-- 元素及其子元素都不会再重新渲染 -->
<div v-once>
<h2>{{ count }}</h2>
</div>
v-text
<h2>{{ msg }}</h2>
<!-- 等价于 -->
<h2 v-text="msg"></h2>
v-html
vue在解析模板的时候,会将data中的数据当做字符串进行解析
如果data中的数据是一段html标签的时候,vue依旧会将其作为字符串去进行渲染
如果需要vue将其作为html标签去渲染的时候,可以使用v-html
但是因为这段数据可能来自于第三方,所以为了避免XSS攻击,请确保这些数据的可靠性
<!--<h2>Hello World</h2> -->
<h2>{{ msg }}</h2>
<!-- Hello World -->
<h2 v-html="msg"></h2>
v-pre
v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签
v-pre可以跳过不需要编译的节点,加快编译的速度
<h2 v-pre>{{ msg }}</h2>
<h2>{{ msg }}</h2>
v-bind
V-bind ---> 可以动态绑定属性 ---> 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式
<a v-bind:href="link">google</a>
<!-- 简写 ===> 语法糖 -->
<a :href="link">google</a>
使用v-bind绑定class
-
普通绑定
<span :class="active">Hello World</span> -
对象语法
<!-- 对象语法: {样式: boolean值} boolean值为true的时候,会显示样式, 为false的时候,不显示样式 --> <h2 :class="{active: isActive}">Hello World</h2> <!-- 对象中的key可以是变量 --> <h2 :class="{[active]: isActive}">Hello World</h2> <!-- 也可以有多个键值对 --> <h2 :class="{active: isActive, foo: isFoo}">Hello World</h2> <!-- 默认的class和动态的class结合 --> <h2 class="foo" :class="{active: isActive}">Hello World</h2> <!-- 抽离为一个单独的对象 --> <h2 :class="classObj">Hello World</h2> <!-- 抽离为方法或计算属性 --> <h2 :class="getClassObj()">Hello World</h2> -
数组语法
<!-- 数组中可以是字符串,也可以是变量 --> <h2 :class="['foo', active]">Hello World</h2> <!-- 可以是三目运算符 --> <h2 :class="['foo', isActive ? 'active' : '']">Hello World</h2> <!-- 数组中某一项的返回值是boolean,无论是true还是false,这一项就不会在样式中显示 --> <h2 :class="['foo', isActive && 'active']">Hello World</h2> <!-- 数组中可以嵌套对象语法 --> <h2 :class="['foo', { 'active': isActive }]">Hello World</h2>
使用v-bind绑定style
可以利用v-bind:style来绑定一些CSS内联样式
CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名
-
对象语法
<!-- 属性值要使用字符串包裹,不然会被作为变量去进行解析 --> <h2 :style="{color: 'red', backgroundColor: 'gray'}">Hello World</h2> <!-- 属性名可以使用驼峰或短划法,如果是短划线需要使用引号将属性名进行包裹 --> <h2 :style="{color: 'red', 'background-color': 'gray'}">Hello World</h2> -
数组语法
<!-- 对象数组中的每一项都是一个style对象,可以直接写,也可以抽离成一个对象来引用 --> <h2 :style="[{color: 'red'}, {backgroundColor: 'gray'}]">Hello World</h2>
动态绑定属性
如果属性名称不是固定的,我们可以使用 :[属性名]=“值” 的格式来定义
这种绑定的方式,我们称之为动态绑定属性
<!--
1. 属性名 要么是全小写,要么是中划线写法,因为html不区分大小写,所以在HTML模板中,属性名会被转换为全小写(propertyName -> propertyname)
2. 属性名如果是key的时候,key会被vue作为特殊属性在元素更新的时候使用,所以最终不会被渲染在元素的属性上
3. 使用动态绑定属性,就意味着属性名一定是变量,所以会使用v-bind
此时如果值是字符串的时候,需要手动加上引号,避免值被作为变量进行解析
如果不是有v-bind,此时vue会将[xxx]作为普通字符串属性名进行解析,而这不是一个合法的属性名
-->
<h2 :[name]="'propertyValue'">Hello World</h2>
绑定一个对象
如果我们希望将一个对象的所有属性,绑定到元素上的时候,可以直接绑定一个对象,vue在解析的时候会将对象展开后在进行传递,这对于传递props是十分有帮助的。
<!-- <h2 name="Klaus" age="23">Hello World</h2> -->
<h2 v-bind="userInfo">Hello World</h2>
<!-- 简写 --- 语法糖 -->
<h2 :="userInfo">Hello World</h2>
v-on
在前端开发中,我们需要经常和用户进行各种各样的交互
在Vue中如何监听事件 就需要使用v-on指令
<button v-on:click="handleClick">click me</button>
<!-- 简写 -->
<button @click="handleClick">click me</button>
<!-- v-on 的属性值可以是 function | inline statement | object -->
<!-- function -->
<button v-on:click="handleClick">click me</button>
<!-- inline statement -->
<button v-on:click="count++">{{ count }}</button>
<!-- object --- 用于同时绑定多个事件 -->
<button v-on="{ click: handleClick, mouseup: handleMouseUp }">click me</button>
参数传递
<!-- 如果函数没有任何的参数,那么vue会默认给事件处理函数一个参数,即事件对象event -->
<button v-on:click="handleClick">click me</button>
methods: {
handleClick(e) {
console.log(e)
}
}
<!--
如果函数传递了参数,此时如果需要再获取事件参数对象的时候,需要自己手动传入$event
$event 是vue封装好的特殊变量,表示的就是对应事件的事件对象
-->
<button v-on:click="handleClick('msg', $event)">click me</button>
methods: {
handleClick(msg, e) {
console.log(e, msg)
}
}
事件修饰符
v-on支持修饰符,修饰符相当于对事件进行了一些特殊的处理
| 修饰符 | 作用 | 备注 |
|---|---|---|
| .stop | 调用 event.stopPropagation() | |
| .prevent | 调用 event.preventDefault() | |
| .capture | 添加事件侦听器时使用 capture 模式 | |
| .self | 只当事件是从侦听器绑定的元素本身触发时才触发回 | |
| .{keyAlias} | 仅当事件是从特定键触发时才触发回调 | keyAlias表示的是按键别名, 如enter,delete, tab, space ... 等 |
| .once | 只触发一次回调 | |
| .left | 只当点击鼠标左键时触发 | |
| .right | 只当点击鼠标右键时触发 | |
| .middle | 只当点击鼠标中键时触发 | |
| .passive | { passive: true } 模式添加侦听器 | 表示在进行事件处理的时候,显示的告诉浏览器, 不会阻止默认事件,即不需要去检测是否有阻止默认行为 这对于一些会频繁调用多次的事件(如scroll, mousemove等)会有性能提升的效果 |
<div @click="handleDIVClick">
<button @click.stop="handleBtnClick">click me</button>
</div>
字符串模板和DOM模板
字符串模板
字符串模板就是写在vue中的template中定义的模板
- vue的单文件组件模板
- 定义组件时template属性值的模板(没有被抽取出去的时候)
字符串模板不会在页面初始化参与页面的渲染,会被vue进行解析编译之后再被浏览器渲染,所以不受限于html不区分大小写的影响。
Vue.component('Cpn', {
// MyComponent 定义在template中,会先经过vue的解析再渲染,所以其命名不受限于html不区分大小写的影响
template: '<div MyId="123"><MyComponent>hello, world</MyComponent></div>'
})
<div id="app">
<Cpn />
</div>
dom模板
dom模板(又被称为Html模板)
dom模板就是写在html文件中,一打开就会被浏览器进行解析渲染的,即在经过vue解析之前就会先被浏览器所解析
因为html不区分大小写,所以此时类似于myComponent会被浏览器转换为mycomponent,此时在交给vue去进行解析的时候就会出现问题
<html>
<head>
<meta charset="utf-8">
<title>Vue Component</title>
</head>
<body>
<div id="app">
Hello Vue
<MyComponent></MyComponent>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script >
// MyComponent被解析为了mycomponent,所以vue找不到MyComponent这个组件,会报错
Vue.component('MyComponent', {
template: '<div>组件内容</div>'
});
new Vue ({
el: '#app'
});
</script>
</body>
</html>
因此vue推荐在使用组件的时候,使用中划线的方式去使用(如my-component),而不是使用驼峰法(如MyComponent)的方式去使用。
扩展
在html中有一些属性比较特别,它就是驼峰定义的(例如svg标签中的viewBox属性),所以以驼峰方式使用的时候不会有任何的问题
<svg style="width:150px; height:300px" viewBox="0 0 400 400">
<circle cx="200" cy="200" r="200" fill="#fdd" stroke="none"></circle>
</svg>
但是有的时候,我们希望它和其它属性一样都使用中划线去进行定义,为了正常解析这类标签,vue提供了camel修饰符
.camel 修饰符允许在使用 DOM 模板时将 kebab-case property 转换为camelCase property,
在使用字符串模板或通过 vue-loader 编译时,无需使用 .camel,因为此时vue会帮助我们处理好。
<!--
:view-box.camel 会被编译为 viewBox
ps: 使用camel修饰符的时候,必须是在v-bind的情况下, :view-box.camel ===> viewBox
如果没有结合v-bind,会被解析为 view-box.camel ===> view-box.camel
-->
<svg style="width:150px; height:300px" :view-box.camel="'0 0 400 400'">
<circle cx="200" cy="200" r="200" fill="#fdd" stroke="none"></circle>
</svg>
<!--
camel修饰符只会在svg标签元素上生效,在其它元素上时,camel修饰符会失效
在本例中,:data-property.camel会被解析为dataproperty
-->
<div :data-property.camel="'value'">Hello Vue</div>