vue第二天
v-text和v-html
目标:更新DOM对象的innerText/innerHTML
语法:
-
v-text="Vue数据变量"
-
v-html="Vue数据变量"
<template>
<div>
<!-- v-text:作用 设置标签内容 -->
<!-- 语法:v-text="变量" -->
<!-- 变量声明在data方法返回对象里 -->
<!-- v-text把变量内容作为文本直接显示,不解析内容/标签 -->
<h1 v-text="hello"></h1>
<h1 v-text="helloHTML"></h1>
<!-- v-html:作用,设置标签内容为HTML -->
<!-- 语法:v-html="变量" -->
<!-- 变量声明在data方法返回对象里 -->
<!-- v-html会解析内容中的html标签 -->
<h1 v-html="hello"></h1>
<h1 v-html="helloHTML"></h1>
</div>
</template>
<script>
export default {
data() {
return {
hello: "hello world",
helloHTML: "<button>点我</button>",
};
},
};
</script>
<style>
</style>
总结:二者都可以设置标签显示的内容,v-text不会解析变量内的html标签,v-html会解析。另外二者都会覆盖插值表达式的内容!!
v-show和v-if
二者都可以控制标签的隐藏与显示
语法:
-
v-show="Vue变量" -- 通过控制display:none隐藏(频繁切换使用)
-
v-if="Vue变量" -- 页面显示满足条件的 移除不满足条件的(直接从DOM树上移除 /不满足条件的则被移除) 可以配合v-else-if / v-else使用!! 实现多个条件控制,但必须是相邻节点,中间不能夹杂其他标签。
-------二者需要**(判断Vue变量)**或(判断某些条件)控制显示或隐藏-------
-------v-show或v-if, 给变量赋予true/false, 显示/隐藏-----
例:
<template>
<div>
<!-- v-show -->
<!-- 作用:控制标签显示和隐藏 -->
<!-- v-show语法,v-show="表达式" -->
<!-- v-show通过控制display: none属性来控制显示隐藏 -->
<h1> v-show </h1>
<h2 v-show="age >= 18">成年人</h2>
<h2 v-show="age < 18">未成年</h2>
<!-- v-if -->
<!-- 作用:控制标签显示和隐藏 -->
<!-- v-if语法:v-if="表达式" -->
<!-- v-if通过控制是否插入标签来显示隐藏 -->
<h1> v-if </h1>
<h2 v-if="age >= 18">成年人</h2>
<h2 v-if="age < 18">未成年</h2>
</div>
</template>
<script>
export default {
data() {
return {
age: 18,
};
},
};
</script>
<style>
</style>
v-if和v-else-if / v-else
v-if和v-else-if / v-else搭配使用示例:
<template>
<div>
<input type="text" v-model="age" />
<!-- v-if和v-else可以搭配使用 --必须是相邻节点 -->
<h2 v-if="age < 18">给你甜甜圈</h2>
<h2 v-else>给你快乐水</h2>
<!-- v-if可以和多个v-else-if搭配使用,实现多个条件控制 -->
<!-- 多个条件控制可以使用v-else结尾 -->
<!-- v-else是可选的 -->
<h2 v-if="age < 18">甜甜圈</h2>
<h2 v-else-if="age < 60">快乐水</h2>
<h2 v-else-if="age < 100">脑白金</h2>
<h2 v-else>虫草</h2>
</div>
</template>
<script>
export default {
data() {
return {
age: 18,
};
},
};
</script>
<style>
</style>
折叠面板案例:
<template>
<div>
<h1 class="tc">案例:折叠面板</h1>
<h2>
静夜思
<!-- 根据show的布尔值设置按钮的显示文字 -->
<button @click="toggle"> {{ show ? "收起" : "展开"}}</button>
</h2>
<!-- 使用v-show或者v-if控制内容显示 -->
<div v-show="show">
<p>床前明月光</p>
<p>疑似地上霜</p>
<p>举头望明月</p>
<p>低头思故乡</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
show:"ture",
};
},
methods:{
// 使用取反运算
toggle(){
// console.log('ok');
this.show = !this.show
}
}
};
</script>
<style>
.tc {
text-align: center;
}
</style>
v-for更新监测,key作用
当v-for遍历的数据解构/内容改变,Vue触发v-for的更新
-
情况1: 数组翻转
-
情况2: 数组截取
-
情况3: 更新值
口诀:
-
数组变更方法, 就会导致v-for更新, 页面更新
-
数组非变更方法, 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set()
<template>
<div>
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
<!-- 数组反转 reverse方法会修改原始数组,会触发页面刷新-->
<p><button @click="list.reverse()">反转</button></p>
<!-- 数组截取 slice方法不会修改原始数组,不会触发页面更新-->
<p><button @click="list.slice(0, 2)">数组截取</button></p>
<!-- 更新值 直接通过索引修改数组,不会触发页面更新-->
<p><button @click="list[1] = '宝宝'">通过索引更新数组元素</button></p>
<!-- 更新值 $set方法手动触发更新 -->
<p><button @click="fn">通过$set方法更新数组元素</button></p>
</div>
</template>
<script>
export default {
data() {
return {
list: ["六一", "小宝", "千金"],
};
},
methods: {
fn() {
//this.$set(数组,索引,要更新的值)
this.$set(this.list, 1, "宝宝");
},
},
};
</script>
<style>
</style>
这些方法会触发数组改变, v-for会监测到并更新页面
push()pop()shift()unshift()splice()sort()reverse()
这些方法不会触发v-for更新
slice()filter()concat()
注意: vue不能监测到数组里赋值的动作而更新, 如果需要请使用Vue.set() 或者this.$set(), 或者覆盖整个数组
总结:改变原数组的方法才能让v-for更新
v-for就地更新
就地更新原则,新旧DOM产生后对比, 然后决定是否复用真实DOM/更新内容
v-for的默认行为会尝试原地修改元素而不是移动它们。
虚拟DOM本质是一个JS对象,保存DOM关键信息。 好处是提高DOM更新的性能 ,不频繁操作真实DOM,在内存中找到变化部分,在更新真是DOM(打补丁)!!
key的作用
v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key 来提供一个排序提示
-
无key -- 就地更新
-
有key为索引 -- 就地更新 (但不会报错了😊)
-
有key为id(唯一不重复的字符串或者数值) -- 按照key比较
<template>
<div>
<ul>
<!--有key以后 不再是就地更新 而是按照key比较 key为唯一不变的值 -->
<!-- key的好处是可以配合虚拟DOM提高更新的性能 -->
<!-- key为索引index 还是就地更新 -->
<!-- key为id(唯一值) 按照key作比较 -->
<!-- <li v-for="(item,index) in arr" :key="index"> -->
<li v-for="(item) in arr" :key="item.id">
<p>{{ item.name }}</p>
<p>{{ item.age }}</p>
<p>{{ item.gender }}</p>
</li>
</ul>
<button @click="arr.reverse()">反转</button>
</div>
</template>
<script>
export default {
data() {
return {
arr: [
{
id: 1,
name: "zyz",
age: 23,
gender: "女",
},
{
id: 2,
name: "gyh",
age: 27,
gender: "男",
},
{
id: 3,
name: "baby",
age: 0,
gender: "女",
},
],
};
},
};
</script>
<style>
</style>
v-for更新检测总结
v-for什么时候会更新页面呢?
- 数组采用更新方法, 才导致v-for更新页面
vue是如何提高更新性能的?
- 采用虚拟DOM+key提高更新性能
虚拟DOM是什么?
- 本质是保存dom关键信息的JS对象
如何比较新旧虚拟DOM?
- 根元素改变 – 删除当前DOM树重新建
- 根元素未变, 属性改变 – 更新属性
- 根元素未变, 子元素/内容改变
- 无key – 就地更新 / 有key为索引 -- 就地更新 / 有key 为唯一值– 按key比较
动态class-动态style
动态class--用v-bind给标签class设置动态的值
动态style--给标签动态设置style的值
语法
-
动态class语法: :class="{类名:布尔值}"
⚠️⚠️⚠️类名有横线,加引号.
-
动态style语法: :style="{css属性: 值}"
⚠️⚠️⚠️样式名有横线,加引号或使用小驼峰写法.
动态设置class示例:
<template>
<div>
<!-- 动态设置class -->
<!-- :class="{ 类名: 布尔值}" -->
<!-- 布尔值为true,标签增加类名,为false删除类名 -->
<!-- 可以控制多个类名 -->
<button :class="{ on: isOn, off: !isOn }" @click="fn">开关</button>
</div>
</template>
<script>
export default {
data() {
return {
isOn: false,
};
},
methods: {
fn() {
this.isOn = !this.isOn;
},
},
};
</script>
<style>
.off {
background-color: grey;
}
.on {
background-color: red;
}
</style>
动态设置style示例:
<template>
<div>
<!-- 动态设置样式 -->
<!-- :class="{ 类名:布尔值 }",类名如果包含横线-,采用引号 -->
<!-- 动态设置style -->
<!-- :style="{ 样式名: 样式的值 }",样式名如果带横线,改为小驼峰,也可以使用引号 -->
<button
@click="fontColor = 'blue'"
:style="{ color: fontColor, 'font-size': '60px' }"
:class="{ 'text-center': true, textTop: true }"
>
变色
</button>
</div>
</template>
<script>
export default {
data() {
return {
fontColor: "red",
};
},
};
</script>
<style>
</style>
vue过滤器
vue过滤器定义和使用
作用:转换格式, 过滤器就是一个函数, 传入值返回处理后的值
注:过滤器只能用在, ==插值表达式和v-bind表达式==
局部过滤器--声明在VUE文件data统计的filters对象属性里面
全局过滤器--声明在main.js文件里面 **语法:Vue.filter("过滤器名",方法)**🚨
Vue中的过滤器场景
- 字母转大写, 输入"hello", 输出"HELLO"
- 字符串翻转, "输入hello, world", 输出"dlrow ,olleh"
语法:
-
Vue.filter("过滤器名", (值) => {return "返回处理后的值"})
-
filters: {过滤器名字: (值) => {return "返回处理后的值"}
例子:
- 全局定义字母都大写的过滤器
- 局部定义字符串翻转的过滤器
- ..............
示例:
局部过滤器和全局过滤器(声明在main.js里面的过滤器)
<template>
<div>
<!-- 过滤器作用:转换数据格式 -->
商品价格:{{ price | priceFilter }}
<h2>{{ "hello" | toUpperCase }}</h2>
<!-- 过滤器能使用在插值表达式和v-bind属性里 -->
<!-- :title 是 v-bind方法悬停时显示 -->
<p :title="'hello vue' | toUpperCase">hello vue</p>
</div>
</template>
<script>
export default {
data() {
return {
price: 100,
};
},
// 声明在data同级下的filters对象里
filters: {
//过滤器声明为方法
// 表达式的值是过滤器的第一个参数
priceFilter(num) {
return `¥${num}`;
// 不足十元补0
// return `¥${num < 10 ? "0" + num : num}`;
},
toUpperCase(value) {
return value.toUpperCase();
},
},
};
</script>
<style>
</style>
vue过滤器 传参和多过滤器
目标: 可同时使用多个过滤器, 或者给过滤器传参
语法:
- 过滤器传参: vue变量 | 过滤器(实参)
- 多个过滤器: vue变量 | 过滤器1 | 过滤器2
vue计算属性
一个变量的值, 依赖另外一些数据计算而来的结果
注意⚠️: 计算属性也是vue数据变量, 所以不要和data里重名, 用法和data相同
语法:
computed: {
"计算属性名"() {
return "值"
}
}
例:
<template>
<div>
<!-- 计算属性,作用:根据一些数据计算出来一个属性 -->
<!-- 当计算属性以来的数据变化时,计算属性也会重新运算 -->
<!-- 计算属性是作为变量使用的,不要使用括号的语法 -->
<!-- 计算属性不能和data里的变量重名 -->
<h1>{{ sum }}</h1>
a: <input type="text" v-model.number="a" />
</div>
</template>
<script>
export default {
data() {
return {
a: 10,
b: 20,
};
},
// 计算属性声明在data统计的computed对象里面
computed: {
//计算属性声明为方法
sum() {
return this.a + this.b;
},
},
};
</script>
<style>
</style>
计算属性-缓存
计算属性是基于它们的依赖项的值结果进行缓存的,只要依赖的变量不变, 都直接从缓存取结果
❗计算属性的好处:
-
带缓存
-
依赖项不变,直接从缓存中取
-
一拉想改变,函数自动执行并从新缓存
❗使用场景
- 当变量值依赖其他变量计算而得来采用
计算属性完整写法
计算属性也是变量, 如果想要直接赋值, 需要使用完整写法
computed: {
"属性名": {
<!-- set更新/设置计算属性 -->
set(值){
},
<!-- get获取计算属性 -->
get() {
return "值"
}
}
}
品牌管理案例
<template>
<div class="container">
<div class="row">
<div class="col-12 pt-3">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">编号</th>
<th scope="col">资产名称</th>
<th scope="col">价格</th>
<th scope="col">创建时间</th>
<th scope="col">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="item.id">
<th scope="row">{{ item.id }}</th>
<td>{{ item.name }}</td>
<td :class="{ expensive: item.price > 100 }">{{ item.price }}</td>
<td>{{ item.time | dataFilter }}</td>
<td>
<!-- 删除1.删除按钮,绑定事件 -->
<!-- 删除2.绑定事件获取要删除的元素索引 -->
<button
type="button"
class="btn btn-link"
@click="deleteProduct(index)"
>
删除
</button>
</td>
</tr>
<tr class="bg-light">
<th scope="row">统计</th>
<td colspan="2">总价:{{ totalPrices }}</td>
<td colspan="2">均价:{{ averagePrice }}</td>
</tr>
</tbody>
<!-- 删除4.控制空状态显示 -->
<tfoot v-show="list.length === 0">
<tr>
<td class="text-center" colspan="5">暂无数据</td>
</tr>
</tfoot>
</table>
</div>
</div>
<form class="row align-items-center">
<div class="col-3">
<input
type="text"
class="form-control"
placeholder="资产名称"
v-model="productName"
/>
</div>
<div class="col-3">
<input
type="text"
class="form-control"
placeholder="价格"
v-model.number="productPrice"
/>
</div>
<div class="col-3">
<button
type="submit"
class="btn btn-primary"
@click.prevent="addProperty"
>
添加资产
</button>
</div>
</form>
</div>
</template>
<script>
import moment from "moment";
export default {
name: "App",
data() {
return {
list: [
{
id: 100,
name: "外套",
price: 199,
time: new Date("2010-08-12"),
},
{
id: 101,
name: "裤子",
price: 34,
time: new Date("2013-09-01"),
},
{
id: 102,
name: "鞋",
price: 25.4,
time: new Date("2018-11-22"),
},
{
id: 103,
name: "头发",
price: 19900,
time: new Date("2020-12-12"),
},
],
productName: "",
productPrice: 0,
};
},
computed: {
//计算总价业务相关代码
totalPrices() {
let total = 0;
this.list.forEach((item) => {
total += item.price;
});
return total;
},
// 计算均价业务相关代码
averagePrice() {
let average = this.totalPrices / this.list.length;
return average
}
},
filters: {
dataFilter(time) {
return moment(time).format("YYYY-MM-DD");
},
},
methods: {
addProperty() {
if (!this.productName || !this.productPrice) {
alert("资产名称或价格不能为空");
return;
}
//删除5.处理空数据情况下新增逻辑异常
let id;
if (this.list.length > 0) {
id = this.list[this.list.length - 1].id + 1;
} else {
id = 100;
}
this.list.push({
id,
name: this.productName,
price: this.productPrice,
time: new Date(),
});
(this.productName = ""), (this.productPrice = 0);
},
deleteProduct(index) {
//删除3.删除元素
// console.log(index);
this.list.splice(index, 1);
},
},
};
</script>
<style scoped>
.expensive {
color: red;
}
</style>
全选小选案例
<template>
<div>
<p>全选:<input type="checkbox" v-model="isAll" /></p>
<ul>
<li v-for="item in list" :key="item.id">
<input type="checkbox" v-model="item.checked" /> {{ item.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{
id: 1,
name: "八戒",
checked: false,
},
{
id: 2,
name: "孙悟空",
checked: false,
},
{
id: 3,
name: "唐僧",
checked: false,
},
{
id: 4,
name: "白龙马",
checked: false,
},
],
};
},
computed: {
isAll: {
// set 设置/更新计算属性
set(value) {
this.list.forEach((item) => {
item.checked = value;
});
},
//get 获取计算属性
get() {
let all = true;
this.list.forEach((item) => {
if (item.checked === false) {
all = false;
}
});
return all;
},
},
},
};
</script>
<style>
</style>