Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
在App.vue里引入 TemplateSyntax.vue
components/TemplateSyntax.vue
{{message}}
{{version}}
只要是属性都可以通过 v-bind的形式绑定
高亮
id属性绑定
自定义属性绑定
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
每个绑定都只能包含单个表达式
var a = 10; 不是(不是表达式)
10 > 5 ? 'yes' : 'no' 是
if(a>b){return b;} 不是(不是单个表达式)
v-show:通过 display 来控制其显示和隐藏(display:none/block;)
v-if:通过直接从DOM树删除和创建其结构来控制显示和隐藏
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好
hello world
by world
当 show: false,
因为 v-if
是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用
v-if
。最终的渲染结果将不包含 元素。
Title
Paragraph 1
Paragraph 2
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
那么在上面的代码中切换 loginType
将不会清除用户已经输入的内容。因为两个模板使用了相同的元素, 不会被替换掉——仅仅是替换了它的
placeholder
注意点:在使用v-if和v-else时,中间不能插入其他内容
if
else
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
if
elseif
else
v-else
元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别v-else
,v-else-if
也必须紧跟在带 v-if
或者 v-else-if
的元素之后v-show
不支持
元素,也不支持 v-else
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块v-show
不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好v-if
和 v-for
语法:
v-for="(值变量, 索引变量) in 目标结构"
v-for="值变量 in 目标结构"
目标结构:
可以遍历数组 / 对象 / 数字 / 字符串 (可遍历结构)
注意:
v-for的临时变量名不能用到v-for范围外
谁想循环就把v-for写谁身上
Components/VforDemo.vue
{{item}} -- {{index}}
{{value}}--{{key}}--{{index}}
{{item}}--{{index}}
{{item}}--{{index}}
点击按钮后,
v-for为了提升性能,在更新已渲染过的元素列表时,会采用“就地复用”策略,也正是因为这个策略,在某些时刻会导致我们的数据混乱
数组变更方法(即可以改变原数组的方法,例如:push/pop/shfit/unshifi/splice/sort/reverse), 就会导致v-for更新, 页面更新
数组非变更方法(即不改变原数组的方法,例如:filter/concat/slice), 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set():
拿返回的新数组,直接替换旧数组
例如:在列表前面新增了内容
为了解决这个问题,我们可以在渲染列表的时候给每一个元素加上一个独一无二的key,v-for在更新已经渲染过的元素列表时,会先判断key是否相同,如果相同则复用,如果不同则重新创建
key属性注意点:
不能使用index作为key,因为当列表的内容新增或删除时,index都会发生变化,这就导致了不能很好的复用没有发生改变的元素,大大降低了渲染的效率
-
{{index}} --- {{person.name}}
虚拟DOM:
同级比较-根元素变化-整个dom树删除重建
同级比较-根元素不变-属性改变更新属性
此时会根据有没有 key 属性来进行比较
a.如果没有 key:最大限度尝试就地修改--复用相同类型元素
b.有key属性:基于key的来比较新旧虚拟DOM, 移除key不存在元素,先产生新旧虚拟DOM, 根据key比较, 还是就地更新
c.有key, 值唯一不重复的字符串或数字: 基于key的来比较新旧虚拟DOM, 移除key不存在元素,先产生新旧虚拟DOM, 根据key比较,再插入/删除新的DOM(推荐)
唯一不重复的字符串或者数值
key用法:有id用id, 无id用索引
key的好处?--可以配合虚拟DOM提高更新的性能
d.虚拟DOM总结
v-for什么时候会更新页面呢?
数组采用更新方法, 才导致v-for更新页面
vue是如何提高更新性能的?
采用虚拟DOM+diff算法提高更新性能
虚拟DOM是什么?
本质是保存dom关键信息的JS对象
diff算法如何比较新旧虚拟DOM?
根元素改变 – 删除当前DOM树重新建
根元素未变, 属性改变 – 更新属性
根元素未变, 子元素/内容改变
无key – 就地更新 / 有key – 按key比较
公共部分:
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过
保持在元素上直到关联实例结束编译
和 CSS 规则如 [v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕
[v-cloak] {
display: none
}
const app = Vue.createApp({
data() {
return {
name: '张三'
}
},
template: `
{{name}}
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
v-text:
v-html:
v-text 和 v-html 会覆盖插值表达式
const app = Vue.createApp({
data() {
return {
name: '张三',
message: '我是span'
}
},
template: `
{{name}}
{{message}}
{{message}}
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
在企业开发中想要给元“元素”绑定数据,我们可以使用 {{}} ,v-text,v-html
但是要想给“元素的属性”绑定数据,就必须使用 v-bind
因此 v-bind 的作用是专门用于给“元素的属性”绑定数据的
格式:
v-bind:属性名称=“绑定的数据” 或
:属性名称=“绑定的数据”
特点:
赋值的数据可以是任意一个合法的JS表达式即可
const app = Vue.createApp({
data() {
return {
name: '张三',
message: '我是span'
}
},
template: `
{{name}}
{{message}}
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
注意点:
格式:
:class="['需要绑定的类名',...]"
示例1:
.red {
color: red;
}
示例2:
* {
margin: 0;
padding: 0;
}
.size {
font-size: 20px;
}
.color {
color: red;
}
.active {
background: skyblue;
}
const app = Vue.createApp({
data() {
return {
name: '张三',
message: '我是span',
flag: false,
obj: {
'size': true,
'color': false,
'active': false
}
}
},
template: `
我是p标签
我是p1标签
我是p2标签
我是p3标签
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
注意:
const app = Vue.createApp({
data() {
return {
name: '张三',
message: '我是span',
flag: false,
obj1: {
'font-size': '30px',
'color': 'red',
},
obj2: {
'background-color': 'skyblue'
}
}
},
template: `
我是p标签
我是p标签
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
专门用于给DOM元素/标签绑定监听事件
格式:
v-on:/@事件名=“要执行的少量代码"
v-on:/@事件名=“methods中的函数名"
v-on:/@事件名=“methods中的函数名(实参)"
方法在methods选项定义
v-on: 等价于 @
你要购买的商品数量为:{{count}}
vue事件处理函数中拿到事件对象:
语法:
无传参, 通过形参直接接收
传参, 通过$event指代事件对象传给事件处理函数
在事件中有很多东西需要我们处理,例如事件冒泡、事件捕获、阻止默认行为等
那么在Vue中我们可以通过v-on修饰符来处理
常见修饰符:
注意:
* {
margin: 0;
padding: 0;
}
.a {
width: 100px;
height: 100px;
background: red;
}
.b {
width: 80px;
height: 80px;
background: skyblue;
}
const app = Vue.createApp({
data() {
return {
gender: 'male'
}
},
methods: {
myFn(name, age, e) {
// alert('myfn');
console.log('myfn');
console.log(name, age, e, this.gender);
},
myFn1() {
console.log("父亲");
},
myFn2() {
console.log("儿子");
},
},
template: `
我是a标签
我是a
我是b
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
a.系统修饰符:
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
middle
.ctrl
.alt
.shift
.meta
在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞).exact
允许你控制由精确的系统修饰符组合触发的事件
示例:
const app = Vue.createApp({
data() {
return {
}
},
methods: {
myFn() {
console.log('lng');
}
},
// v-on: == @
template: `
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
b.按键修饰符:
Vue.config.keyCodes = {
v: 86,
f1: 112,
// camelCase 不可用
mediaPlayPause: 179,
// 取而代之的是 kebab-case 且用双引号括起来
"media-play-pause": 179,
up: [38, 87]
}
const app = Vue.createApp({
data() {
return {
}
},
methods: {
myFn() {
console.log('lng');
}
},
// v-on: == @
template: `
`
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
注意:
在自定义指令的时候,在指定指令名称时,不需要写v-
指令可以在不同生命周期阶段执行 bind(指令被绑定到元素上的时候执行)、inserted(绑定指令的元素被添加到父元素上时执行)...
或,
为了便于使用,我们可以在项目根目录 src 下新建一个 directives 文件夹,在文件夹里新建一个 index.js文件,将全局指令相关的代码写入该文件,再在 main.js 里通过 import 的方式引入即可
App.vue
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import "./dircectives/index"
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
MyDirective.vue
src/directives/index.js
import Vue from "vue"
//全局指令
Vue.directive('focus', {
//指令钩子函数 当被绑定的元素插入到 DOM 中时……
inserted: function(el) {
// 聚焦元素
el.focus()
}
})
//高亮显示
//Vue.directive('red', {
// inserted: function(el) {
// el.style.color = "#ff0000";
// }
// })
//自定义指令 directive
const app = Vue.createApp({
data() {
return {
curColor: 'green'
}
},
template: `
我是段落
我是段落1
`
});
//全局自定义指令
app.directive('color', {
mounted(el, obj) {
// el.style.color = "red";
el.style.color = obj.value;
}
});
//将组件挂到root节点里,即只作用在id等于root的div元素里
//vm 代表的就是 vue 应用的根组件
const vm = app.mount('#root');
//vm.$data 获得数据
// vm.$data.message = 'root';
.header {
position: absolute;
}
.header {
position: absolute;
}