文章目录
Mustache语法
如果我们希望把数据显示到模板(template)中,使用最多的语法是 “Mustache”语法 (双大括号) 的文本插值。
- 并且我们前端提到过,data返回的对象是有添加到Vue的响应式系统中;
- 当data中的数据发生改变时,对应的内容也会发生更新。
- 当然,Mustache中不仅仅可以是data中的属性,也可以是一个JavaScript的表达式。
// 正确写法
<!-- 1.基本使用 -->
<h2>{{ message }}</h2>
<h2>当前计数: {{ counter }} </h2>
<!-- 2.表达式 -->
<h2>计数双倍: {{ counter * 2 }}</h2>
<h2>展示的信息: {{ info.split(" ") }}</h2>
<!-- 3.三元运算符 -->
<h2>{{ age >= 18? "成年人": "未成年人" }}</h2>
<!-- 4.调用methods中函数 -->
<h2>{{ formatDate(time) }}</h2>
// 错误写法
<!-- 5.注意: 不能定义语句 -->
<!-- <h2>{{ const name = "hello" }}</h2> -->
<!-- 6.注意: 控制流的if语句也是不支持的,可以使用三元运算符 -->
<!-- <h2>{{ if (true) return { message } }}</h2> -->
常用指令
v-once
v-once
用于指定元素或者组件只渲染一次
- 当数据发生变化时,元素或者组件以及其所有的子元素将被视为静态内容并且跳过;
- 该指令可以用于性能优化;
- 如果是子节点,也是只会渲染一次:
// v-once作用于元素本身
<template>
<div>
<h2 v-once>{{ count }}</h2>
<button @click="change">修改count</button>
</div>
</template>
// v-on作用于元素的父元素
<template>
<div v-once>
<h2>{{ count }}</h2>
<button @click="change">修改count</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
change() {
this.count++
}
}
}
</script>
结果展示:这时候不管怎么点击按钮,count的值都不会改变
v-text
v-text
用于更新元素的 textContent:
<template>
<span v-text='message'></span>
//等价于
<span >{{ message }}</span>
</template>
<script>
export default {
data() {
return {
message: "Hello"
}
}
}
</script>
v-html
默认情况下,如果我们展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析。
如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示;
<template>
<h2>{{ content }}</h2> //<span>hello</span>
<h2 v-html="content"></h2> //hello
</template>
<script>
export default {
data() {
return {
content: `<span>hello</span>`
}
}
}
</script>
v-pre
- v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签:
- 跳过不需要编译的节点,加快编译的速度;
<div v-pre>
<h2>{{ message }}</h2> //{{ message }}
<p>{{}}</p> //{{}}
</div>
v-cloak
- 这个指令保持在元素上直到关联组件实例结束编译。
- 和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕。
举个栗子!!!
//3秒之后才会在浏览器中显示Hello
<h2 v-cloak>{{message}}</h2>
setTimeout(() => {
const app = Vue.createApp({
data: function() {
return {
message: "Hello"
}
},
})
app.mount("#app")
}, 3000)
v-bind
1.基本属性
- v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值;
- 在开发中,有哪些属性需要动态进行绑定呢?
- 比如图片的链接src、网站的链接href、动态绑定一些类、样式等等
- v-bind有一个对应的语法糖,也就是简写方式(:)。
<!-- 1.绑定img的src属性 -->
<img v-bind:src="src" alt="">
<!-- 语法糖: v-bind -> : -->
<img :src="src" alt="">
<!-- 2.绑定a的href属性 -->
<a :href="href">百度一下</a>
2.绑定class
- 在开发中,有时候我们的元素class也是动态的,比如:
- 当数据为某个状态时,字体显示红色。
- 当数据另一个状态时,字体显示黑色。
- 绑定class有两种方式:
- 对象语法:我们可以传给 :class (v-bind:class 的简写) 一个对象,以动态地切换 class。
- 数组语法:我们可以把一个数组传给 :class,以应用一个 class 列表;
举个栗子!!
//isActive改变时切换class,为true时切换
<!-- 1.基本绑定class -->
<h2 :class="classes"></h2>
<!-- 2.动态class可以写对象语法 -->
<h2 :class=" isActive ? 'active': '' " ></h2>
<!-- 2.1.对象语法的基本使用(掌握) -->
<h2 :class="{ active: isActive }" ></h2>
<!-- 2.2.对象语法的多个键值对 -->
<h2 :class="{ active: isActive, abc: true, cba: false }" ></h2>
<!-- 2.3.动态绑定的class是可以和普通的class同时的使用 -->
<h2 class="common" :class="{ active: isActive, abc: true, cba: false }" ></h2>
<!-- 2.4.动态绑定的class是可以和普通的class同时的使用 -->
<h2 class="common" :class="getDynamicClasses()" ></h2>
<!-- 3.动态class可以写数组语法(了解) -->
<h2 :class="['abc', 'cba']">Hello Array</h2>
<h2 :class="['abc', className]">Hello Array</h2>
<h2 :class="['abc', className, isActive? 'active': '']">Hello Array</h2>
<h2 :class="['abc', className, { active: isActive }]">Hello Array</h2>
/*
methods: {
data: function() {
return {
isActive: false,
className: "why"
}
},
btnClick: function() {
this.isActive = !this.isActive
},
getDynamicClasses: function() {
return { active: this.isActive, abc: true, cba: false }
}
}
*/
3.绑定style
- 我们可以利用v-bind:style来绑定一些CSS内联样式:
- 这次因为某些样式我们需要根据数据动态来决定;
- 比如某段文字的颜色,大小等等;
- CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名;
- 绑定class有两种方式:
- 对象语法
- 数组语法
<!-- 1.普通的html写法 -->
<h2 style="color: red; font-size: 30px;">哈哈</h2>
<!-- 2.基本使用:传入一个对象,并且对象的内容都是确定的 -->
<h2 v-bind:style="{ color: 'red', fontSize: '30px' ,'background-color' : 'blue'}">哈哈</h2>
<!-- 3.变量数据:传入一个对象,值会来自data中 -->
<h2 v-bind:style="{ color: 'red', fontSize: size + 'px' ,'background-color' : 'blue'}">哈哈</h2>
<!-- 4对象数据:直接在data中定义好对象在这里使用 -->
<h2 :style="objStyle">哈哈</h2>
<!-- 5.数组语法:可以将多个样式的对象都应用到同一个元素上 -->
<h2 :style="[objStyle]">哈哈</h2>
<h2 :style="[objStyle, { backgroundColor: 'purple' }]">哈哈</h2>
<h2 :style="[objStyle1, objStyle1]">哈哈</h2>
4.绑定动态属性
- 在某些情况下,我们属性的名称可能也不是固定的:
- 前端我们无论绑定src、href、class、style,属性名称都是固定的;
- 如果属性名称不是固定的,我们可以使用 :[属性名]=“值”的格式来定义;
- 这种绑定的方式,我们称之为动态绑定属性;
<h2 :[name]="value">Hello World</h2>
5.绑定对象
- 如果我们希望将一个对象的所有属性,绑定到元素上的所有属性,应该怎么做呢?
- 非常简单,我们可以直接使用 v-bind绑定一个对象;
<!-- v-bind绑定对象: 给组件传递参数 -->
<h2 v-bind="infos">{{message}}</h2>
v-on
1.用法
- 在前端开发中,我们需要经常和用户进行各种各样的交互:
- 这个时候,我们就必须监听用户发生的事件,比如点击、拖拽、键盘事件等等
- 在Vue中如何监听事件呢?使用v-on指令。
2.基本使用
- 我们可以使用v-on来监听一下点击的事件:
<!-- 基本的写法 -->
<div class="box" v-on:click="divClick"></div>
<!-- 绑定一个表达式 -->
<button @click="counter++">+1</button>
- v-on:click可以写成@click,是它的语法糖写法:
<!-- 语法糖写法(重点掌握) -->
<div class="box" @click="divClick"></div>
- 当然,我们也可以绑定其他的事件:
<!-- 绑定其他方法(掌握) -->
<div class="box" @mousemove="divMousemove"></div>
- 如果我们希望一个元素绑定多个事件,这个时候可以传入一个对象:
<div class="box" @click="divClick" @mousemove="divMousemove"></div>
<div class="box" v-on="{ click: divClick, mousemove: divMousemove }"></div>
<div class="box" @="{ click: divClick, mousemove: divMousemove }"></div>
3.参数传递
- 当通过methods中定义方法,以供@click调用时,需要注意参数问题:
- 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。
- 但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
- 情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。
<!-- 1.默认传递event对象 -->
<button @click="btn1Click">按钮1</button>
<!-- 2.只有自己的参数 -->
<button @click="btn2Click('zy', 18)">按钮2</button>
<!-- 3.自己的参数和event对象 -->
<!-- 在模板中想要明确的获取event对象: $event -->
<button @click="btn3Click('zy', 18, $event)">按钮3</button>
methods: {
// 1.默认参数: event对象
// 总结: 如果在绑定事件的时候, 没有传递任何的参数, 那么event对象会被默认传递进来
btn1Click(event) {
console.log("btn1Click:", event)
},
// 2.明确参数:
btn2Click(name, age) {
console.log("btn2Click:", name, age)
},
// 3.明确参数+event对象
btn3Click(name, age, event) {
console.log("btn3Click:", name, age, event)
}
}
4.修饰符
- v-on支持修饰符,修饰符相当于对事件进行了一些特殊的处理:
- .stop -调用 event.stopPropagation()。
- .prevent -调用 event.preventDefault()。
- .capture -添加事件侦听器时使用 capture 模式。
- .self -只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .{keyAlias} -仅当事件是从特定键触发时才触发回调。
- .once -只触发一次回调。
- .left -只当点击鼠标左键时触发。
- .right -只当点击鼠标右键时触发。
- .middle -只当点击鼠标中键时触发。
- .passive - { passive: true }模式添加侦听器
<div class="box" @click="divClick">
<button @click.stop="btnClick">按钮</button>
</div>
methods: {
btnClick(event) {
console.log("btnClick")
},
divClick() {
console.log("divClick")
}
}
v-if,v-else,v-else-if
1.条件渲染
- 在某些情况下,我们需要根据当前的条件决定某些元素或组件是否渲染,这个时候我们就需要进行条件判断了。
- Vue提供了下面的指令来进行条件判断:
- v-if
- v-else
- v-else-if
- v-show
- v-if、v-else、v-else-if用于根据条件来渲染某一块的内容:
- 这些内容只有在条件为true时,才会被渲染出来;
- 这三个指令与JavaScript的条件语句if、else、else if类似;
2.v-if
- v-if的渲染原理:
- v-if是惰性的;
- 当条件为false时,其判断的内容完全不会被渲染或者会被销毁掉;
- 当条件为true时,才会真正渲染条件块中的内容;
<!-- v-if="条件" -->
<div class="info" v-if="Object.keys(info).length">
<h2>个人信息</h2>
<ul>
<li>姓名: {{info.name}}</li>
<li>年龄: {{info.age}}</li>
</ul>
</div>
data() {
return {
info: {name:"abc",age:18}
}
}
3.v-else
<!-- v-if="条件" -->
<div class="info" v-if="Object.keys(info).length">
<h2>个人信息</h2>
<ul>
<li>姓名: {{info.name}}</li>
<li>年龄: {{info.age}}</li>
</ul>
</div>
<!-- v-else -->
<div v-else>
<h2>没有输入个人信息</h2>
<p>请输入个人信息后, 再进行展示~</p>
</div>
4.v-else-if
//从date中得到score
<h1 v-if="score > 90">优秀</h1>
<h2 v-else-if="score > 80">良好</h2>
<h3 v-else-if="score >= 60">及格</h3>
<h4 v-else>不及格</h4>
2.template元素
- 因为v-if是一个指令,所以必须将其添加到一个元素上:
- 但是如果我们希望切换的是多个元素呢?
- 此时我们渲染div,但是我们并不希望div这种元素被渲染;
- 这个时候,我们可以选择使用template;
- template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来:
v-show
1.用法
- v-show和v-if的用法看起来是一致的,也是根据一个条件决定是否显示元素或者组件:
<div v-show="isShowCode">哈哈哈</div>
1.v-show和v-if的区别
- 首先,在用法上的区别:
- v-show是不支持template;
- v-show不可以和v-else一起使用;
- 其次,本质的区别:
- v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换;
- v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;
- 开发中如何进行选择呢?
- 如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show;
- 如果不会频繁的发生切换,那么使用v-if;
v-for
1.列表渲染
- 在真实开发中,我们往往会从服务器拿到一组数据,并且需要对其进行渲染。
- 这个时候我们可以使用v-for来完成;
- v-for类似于JavaScript的for循环,可以用于遍历一组数据;
2.基本使用
- v-for的基本格式是 “item in 数组”:
- 数组通常是来自data或者prop,也可以是其他方式;
- item是我们给每项元素起的一个别名,这个别名可以自己来定义;
- 我们知道,在遍历一个数组的时候会经常需要拿到数组的索引:
- 如果我们需要索引,可以使用格式: “(item, index) in 数组”;
- 注意上面的顺序:数组元素项item是在前面的,索引项index是在后面的;
//movies是个数组,来自data
<h2>电影列表</h2>
<ul>
<li v-for="item in movies">{{ item }}</li>
<li v-for="(item, index) in movies">{{ index }}-{{ item }}</li>
</ul>
3.支持的类型
- v-for也支持遍历对象,并且支持有一二三个参数:
- 一个参数: “value in object”;
- 二个参数: “(value, key) in object”;
- 三个参数: “(value, key, index) in object”;
<!-- 遍历对象 -->
<ul>
<li v-for="(value,key,index) in info">
{{value}}-{{key}}-{{index}}
</li>
</ul>
- v-for同时也支持数字的遍历:
- 每一个item都是一个数字;
<!-- 遍历数字 -->
<ul>
<li v-for="item in 10">{{item}}</li>
</ul>
- v-for也可以遍历其他可迭代对象(Iterable)
4.template元素
- 类似于v-if,你可以使用 template 元素来循环渲染一段包含多个元素的内容:
- 我们使用template来对多个元素进行包裹,而不是使用div来完成;
<template id="app">
<ul>
<li v-for="item in 10">{{item}}</li>
</ul>
</template>
5.数组更新检测
- Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。
- 这些被包裹过的方法包括:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
- 替换数组的方法
- 上面的方法会直接修改原来的数组;
- 但是某些方法不会替换原来的数组,而是会生成新的数组,比如 filter()、concat() 和 slice();
注意!!不修改原数组的方法是无法进行侦听(watch)的
//names是个数组,值来自data
<div id="app">
<ul>
<li v-for="item in names">{{ item }}</li>
</ul>
<button @click="changeArray">修改数组</button>
</div>
methods: {
changeArray() {
// 1.直接将数组修改为一个新的数组
this.names = ["why", "kobe"]
// 2.通过一些数组的方法, 修改数组中的元素
this.names.push("why")
this.names.pop()
this.names.splice(2, 1, "why")
this.names.sort()
this.names.reverse()
// 3.不修改原数组的方法是不能侦听(watch)
const newNames = this.names.map(item => item + "why")
this.names = newNames
}
6.key的作用
- 在使用v-for进行列表渲染时,我们通常会给元素或者组件绑定一个key属性。
- 这个key属性有什么作用呢?我们先来看一下官方的解释:
- key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
- 如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;
- 而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;
- 官方的解释对于初学者来说并不好理解,比如下面的问题:
- 什么是新旧nodes,什么是VNode?
- 没有key的时候,如何尝试修改和复用的?
- 有key的时候,如何基于key重新排列的?
(1)VNode
- 我们先来解释一下VNode的概念:
- 因为目前我还没有比较完整的学习组件的概念,所以目前我们先理解HTML元素创建出来的VNode;
- VNode的全称是Virtual Node,也就是虚拟节点;
- 事实上,无论是组件还是元素,它们最终在Vue中表示出来的都是一个个VNode;
- VNode的本质是一个JavaScript的对象;
<div class="title" style="font-size: 30px; color: red;">哈哈哈</div>
const vnode = {
type: "div",
props: {
class: "title",
style: {
"font-size": "30px",
color: red,
},
},
children: "哈哈哈",
};
(2)虚拟DOM
- 如果我们不只是一个简单的div,而是有一大堆的元素,那么它们应该会形成一个VNode Tree:
(3)案例
这个案例是!!!:
data中有个数组letters: [“a”, “b”, “c”, “d”],
设置一个按钮,按钮绑定一个insertF方法,当我点击按钮时会在"b"和"c"中间插一个"f"。
- 没有key:
- c和d来说它们事实上并不需要有任何的改动;
- 但是因为我们的c被f所使用了,所有后续所有的内容都要一次进行改动,并且最后进行新增;
-
有key:
-
第一步的操作是从头开始进行遍历、比较:
-
a和b是一致的会继续进行比较;
-
c和f因为key不一致,所以就会break跳出循环;
-
第二步的操作是从尾部开始进行遍历、比较:
-
第三步是如果旧节点遍历完毕,但是依然有新的节点,那么就新增节点:
-
第四步是如果新的节点遍历完毕,但是依然有旧的节点,那么就移除旧节点:
-
第五步是最特色的情况,中间还有很多未知的或者乱序的节点:
v-model
1.基本使用
- 表单提交是开发中非常常见的功能,也是和用户交互的重要手段:
- 比如用户在登录、注册时需要提交账号密码;
- 比如用户在检索、创建、更新信息时,需要提交一些数据;
- 这些都要求我们可以在代码逻辑中获取到用户提交的数据,我们通常会使用v-model指令来完成:
- v-model指令可以在表单 input、textarea以及select元素上创建双向数据绑定;
- 它会根据控件类型自动选取正确的方法来更新元素;
- 尽管有些神奇,但 v-model 本质上是语法糖,它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理;
<!-- message来自data -->
<!-- inputChange来自methods -->
<!-- 1.手动的实现了双向绑定 -->
<input type="text" :value="message" @input="inputChange">
methods: {
inputChange(event) {
this.message = event.target.value
}
}
<!-- 2.v-model实现双向绑定 -->
<input type="text" v-model="message">
<h2>{{message}}</h2>
2.绑定原理
- v-model的原理其实是背后有两个操作:
- v-bind绑定value属性的值;
- v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;
<input v-model="searchText"></input>
//等价于
<input :value="searchText" @input="searchText = $event.target.value"></input>
3.绑定radio
- v-model绑定radio,用于选择其中一项;
//gender来自data,是female
<div id="app">
<!-- <div class="gender"> -->
<label for="male">
<input id="male" type="radio" v-model="gender" value="male"> 男
</label>
<label for="female">
<input id="female" type="radio" v-model="gender" value="female"> 女
</label>
<h2>gender当前的值是: {{gender}}</h2>
<!-- </div> -->
</div>
4.绑定checkbox
- 我们来看一下v-model绑定checkbox:单个勾选框和多个勾选框
- 单个勾选框:
- v-model即为布尔值。
- 此时input的value属性并不影响v-model的值。
//isAgree来自data,是false
<div id="app">
<!-- checkbox单选框: 绑定到属性中的值是一个Boolean -->
<label for="agree">
<input id="agree" type="checkbox" v-model="isAgree"> 同意协议
</label>
<h2>单选框: {{isAgree}}</h2>
<div>
- 多个复选框:
- 当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。
- 当选中某一个时,就会将input的value添加到数组中。
//hobbies来自data,是空数组
<div id="app">
<div class="hobbies">
<h2>请选择你的爱好:</h2>
<label for="sing">
<input id="sing" type="checkbox" v-model="hobbies" value="sing"> 唱
</label>
<label for="jump">
<input id="jump" type="checkbox" v-model="hobbies" value="jump"> 跳
</label>
<h2>hobbies当前值是: {{hobbies}}</h2>
</div>
</div>
5.绑定select
- 和checkbox一样,select也分单选和多选两种情况。
- 单选:只能选中一个值
- v-model绑定的是一个值;
- 当我们选中option中的一个时,会将它对应的value赋值到fruit中;
//fruit来自data,是orange
<div id="app">
<!-- select的单选 -->
<select v-model="fruit">
<option value="apple">苹果</option>
<option value="orange">橘子</option>
<option value="banana">香蕉</option>
</select>
<h2>fruit当前值是: {{fruit}}</h2>
<div>
- 多选:可以选中多个值
- v-model绑定的是一个数组;
- 当选中多个值时,就会将选中的option对应的value添加到数组fruits中;
//fruits来自data,是空数组
<div id="app">
<!-- select的多选 -->
<select multiple size="3" v-model="fruits">
<option value="apple">苹果</option>
<option value="orange">橘子</option>
<option value="banana">香蕉</option>
</select>
<h2>fruits当前值是: {{fruits}}</h2>
</div>
6.绑定textarea
<div id="app">
<textarea cols="30" rows="10" v-model="content"></textarea>
<p>输入的内容: {{content}}</p>
</div>
7.修饰符
1.lazy
- lazy修饰符是什么作用呢?
- 默认情况下,v-model在进行双向绑定时,绑定的是input事件,那么会在每次内容输入后就将最新的值和绑定的属性进行同步;
- 如果我们在v-model后跟上lazy修饰符,那么会将绑定的事件切换为 change 事件,只有在提交时(比如回车)才会触发;
<input type="text" v-model.lazy="message">
2.number
- 我们先来看一下v-model绑定后的值是什么类型的:
- message总是string类型,即使在我们设置type为number也是string类型;
- 如果我们希望转换为数字类型,那么可以使用 .number 修饰符:
<input type="text" v-model.number="counter">
<h2>counter:{{counter}}-{{typeof counter}}</h2>
- 另外,在我们进行逻辑判断时,如果是一个string类型,在可以转化的情况下会进行隐式转换的:
const score = "100";
if(score > 90){
console.log("优秀");
}
console.log(typeof score);
3.trim
- 如果要自动过滤用户输入的守卫空白字符,可以给v-model添加 trim 修饰符:
<!-- trim: 去除空格 -->
<input type="text" v-model.trim="content">