vue基础-动态class
用v-bind给标签class设置动态的值
语法
- 格式1:<标签 :class="变量" />
- 格式2:<标签 :class="{类名1: 布尔值, 类名2: 布尔值}" />
-
- 如果布尔值为true,就添加对应的类名
说明:可以和静态class共存
示例代码
<style>
#app{width:500px;margin:50px auto;border:3px solid red;}
.box{
border:3px solid black;
margin:5px;
}
.bg-blue{
background-color: blue;
}
.bg-green{
background-color: green;
}
.fs20{font-size:20px;}
.tr{text-align: right;}
</style>
</head>
<body>
<div id="app">
<h3 class="title">v-bind-绑定class</h3>
<!-- 元素自有class和v-bind绑定的class会协同工作,一起生效 -->
<div class="box" v-bind:class="cla ? 'bg-blue': 'bg-green'">
1. 三元表达式
</div>
<!-- 如果对象中的属性值是true,
则把对象中的属性名添加到类名中 -->
<div class="box" :class="claObj">
2. 绑定对象
</div>
<!-- 数组中元素是字符串,
它会把所有的元素全添加到class中 -->
<div class="box" :class="claArr">
3. 绑定数组
</div>
<button @click="hAddClass">补充一个class</button>
</div>
<script>
// v-bind 是用来动态绑定元素的属性,而class也是元素的属性
// 目标: 可以通过动绑定class来控制样式 。
// 方式:
// 1. 三元表达式
// 2. 绑定对象
// 3. 绑定数组
const vm = new Vue({
el: "#app",
// el: document.getElementById("app"),
data: {
cla: false,
claObj: {
fs20: true,
tr: true
},
claArr:['fs20','tr', 'abc']
},
methods: {
hAddClass () {
// 向数组中添加一个类 'c-red'
this.claArr.push('c-red')
}
}
})
</script>
小结
就是把类名保存在vue变量中赋予给标签
vue基础-动态style
目标
给标签动态设置style的值
语法
<标签 :style="{css属性名: 值}" />
- 可以和静态style共存
- 样式中带-属性写成小驼峰
示例代码
<div id="app">
<h3 class="title">v-bind-绑定style</h3>
<!-- 把对象的属性名和属性值直接设置到style中 -->
<div class="box" :style="styleObj">
1. 绑定对象
</div>
<!-- 把数组中的每一个元素(对象),取出来,组成style -->
<div class="box" :style="styleArr">
2. 绑定数组
</div>
<button @click="hBlack">改成黑色的字</button>
</div>
<script>
// v-bind 是用来动态绑定元素的属性,而style也是元素的属性
// 目标: 可以通过动绑定style来控制样式 。
// 方式:
// 1. 绑定对象
// 2. 绑定数组
const vm = new Vue({
el: "#app",
// el: document.getElementById("app"),
data: {
styleObj: {
color:'red',
// 如果属性名有-,则要加''
'background-color':'blue'
},
// 数组中的每一项都是一个对象,其中以键值对的格式设置了style
styleArr:[ {color:'red','font-weight':'bold'}, {'font-size':'50px'} ]
},
methods: {
hBlack () {
// 直接把styleObj中的color设置成black
this.styleObj.color = "black"
}
}
})
</script>
案例-品牌管理(铺增删)
目标
数据铺设, 数据新增和删除
需求
- 把默认数据显示到表格上
- 注意资产超过100的, 都用红色字体标记出来
- 点击删除的a标签, 删除数据;无数据提示
- 实现底部添加资产的功能
注意
- 注意a标签有默认行为-跳转刷新页面(如果有href属性)
- 添加资产时, 提示用户数据不能为空
- form表单里的button的点击事件, 会触发默认表单提交的行为
图示:
- 因为案例使用了bootstrap, 工程化开发, 模块化用npm/yarn下载引入使用
npm i bootstrap
- 静态模板代码(在这个基础上写)
<template>
<div id="app">
<div class="container">
<!-- 顶部搜索框模块 -->
<div class="form-group">
<div class="input-group">
<h4>品牌管理</h4>
</div>
</div>
<!-- 数据表格 -->
<table class="table table-bordered table-hover mt-2">
<thead>
<tr>
<th>编号</th>
<th>资产名称</th>
<th>价格</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr >
<td></td>
<td></td>
<!-- 如果价格超过100,就有red这个类 -->
<td class="red"></td>
<td></td>
<td><a href="#" >删除</a></td>
</tr>
</tbody>
<tfoot >
<tr>
<td colspan="5" style="text-align: center">暂无数据</td>
</tr>
</tfoot>
</table>
<!-- 添加资产 -->
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="资产名称"
/>
</div>
</div>
<div class="form-group">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="价格"
/>
</div>
</div>
<!-- 阻止表单提交 -->
<button class="btn btn-primary">添加资产</button>
</form>
</div>
</div>
</template>
<script>
import "bootstrap/dist/css/bootstrap.css"
export default {
data() {
return {
name: "", // 名称
price: 0, // 价格
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') }
],
};
},
};
</script>
<style >
.red{
color: red;
}
</style>
参考代码
<template>
<div id="app">
<div class="container">
<!-- 顶部搜索框模块 -->
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="搜索" />
</div>
</div>
<!-- 数据表格 -->
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>编号</th>
<th>资产名称</th>
<th>价格</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<!-- 如果价格超过100,就有red这个类 -->
<td :class="{ red: item.price > 100 }">{{ item.price }}</td>
<td>{{ item.time }}</td>
<td><a href="#" @click.prevent="hDel(idx)">删除</a></td>
</tr>
</tbody>
<tfoot v-if="list.length == 0">
<tr>
<td colspan="4" style="text-align: center">暂无数据</td>
</tr>
</tfoot>
</table>
<!-- 添加资产 -->
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input
v-model.trim="name"
type="text"
class="form-control"
placeholder="资产名称"
/>
</div>
</div>
<div class="form-group">
<div class="input-group">
<input
v-model.trim.number="price"
type="text"
class="form-control"
placeholder="价格"
/>
</div>
</div>
<!-- 阻止表单提交 -->
<button class="btn btn-primary" @click.prevent="hAdd">添加资产</button>
</form>
</div>
</div>
</template>
<script>
import "bootstrap/dist/css/bootstrap.css" // 默认找文件夹下的index文件(但是这个不是所以需要写路径)
export default {
data() {
return {
name: "", // 名称
price: 0, // 价格
list: [
{ id: 1, name: "外套", price: 199, time: new Date('2010-08-12')},
{ id: 2, name: "裤子", price: 34, time: new Date('2013-09-01') },
{ id: 3, name: "鞋", price: 25.4, time: new Date('2018-11-22') },
{ id: 4, name: "头发", price: 19900, time: new Date('2020-12-12') },
],
};
},
methods: {
hDel(index) {
// 删除数组中指定位置的元素
this.list.splice(index, 1);
},
hAdd() {
// 收集用户的输入信息
// 简单判空
if (this.name.length == 0 || this.price.length == 0 || this.price < 0) {
alert("请写入正确的名字和价格");
return; // 阻止代码继续向下执行-返回出去这个函数
}
// 向数组中添加一个元素(id应该是数据库产生的, 但是现在是纯前端练习, 所以用数组长度+1)
this.list.push({
id: this.list.length + 1,
name: this.name,
price: this.price,
time: new Date()
});
},
},
};
</script>
<style>
.red{
color: red;
}
</style>
计算属性
使用场景
从已有的数据A中计算等到的新的数据B,使用计算属性。
如果一个结果需要依赖data中的数据,但是需要经过一些逻辑处理,才能得到你想要的数据。此时就可以使用计算属性。
例如:要对给定的字符串做翻转处理之后再来显示
<div id="app">
<!-- 此处逻辑复杂 -->
<h3>{{msg.split('').reverse().join('')}}</h3>
</div>
<script src="./vue.js"></script>
<script>
export default {
data(){
return {
msg: 'javascript'
}
}
}
</script>
定义格式
在vue实例中,补充computed配置项。
{
data(){},
methods: {}
// 声明计算属性
computed: {
//属性名字(计算属性名称)
//属性的值(计算属性处理函数)
计算属性名1 () {
// 对依赖的数据进行处理,且进行return
return
},
计算属性名2 () {
// 对依赖的数据进行处理,且进行return
return
}
}
}
} } })
computed 是vue的配置选项,它的值是一个对象,其中可定义多个计算属性,每个计算属性就是一个函数。
- 属性名称: 计算属性的名称
- 属性的值:计算属性的素材函数
-
- 对需要依赖的数据,进行逻辑上的处理
- 处理完毕后,需要return出去,返回的值就是计算属性的值
使用格式
在两个地方使用:
- 模板
-
- 用插值表达式 {{计算属性名}}
- 用其它指令
- 在实例内
-
- this.计算属性名
示例:颠倒字符串
<div id="app">
<!-- 逻辑复杂 -->
<h3>{{msg.split('').reverse().join('')}}</h3>
<!-- 计算属性 和data类似-->
<h3>{{reverseMsg}}</h3>
</div>
<script src="./vue.js"></script>
<script>
{
data () {
return { msg: 'hi vue' }
},
// 声明计算属性
computed: {
//属性名字(计算属性名称)
//属性的值(计算属性处理函数)
reverseMsg () {
// 对依赖的数据进行处理,且进行return
return this.msg.split('').reverse().join('')
}
}
})
</script>
在模板中使用计算属性,和使用data的方式是一样的。
-
- 虽然在计算属性中声明的是函数,但是在模板中使用,当中数据来使用,不需要加括号。
小结
- 什么时间用:需要对数据进行复杂的逻辑加工,产生新的数据时。
- 定义: 就是一个特殊的配置项computed。其中有多个函数。
- 使用:计算属性的使用方式与data中的数据项一致;
-
- 计算属性-计算:这个值是对原数据进行计算之后得到的新的数据
- 计算属性-属性:它的使用方法与原数据一样。this.计算属性名,{{计算属性名}}
- 执行的时机: 如果计算属性中依赖的数据项变化时,它会自动调用。
computed有缓存
问:
当我们在模板中来显示一份经过对数据项进行复杂计算之后的结果时,我们有两种解决方案:
- 计算属性
- 函数
应该如何选择?
答:
- methods定义函数,如果在模板中使用,每使用一次,就相当于调用了一次,处理逻辑会重新执行。
- computed定义计算属性,如果在模板中使用,使用多次,但是如果依赖的数据不发生改变,计算属性对应的函数不会重新执行。
-
- 计算属性会做缓存,提高渲染的性能。
示例
<div id="app">
<h3>学习计算属性</h3>
<p>计算属性:{{ reversedMsg }}</p>
<p>计算属性:{{ reversedMsg }}</p>
<p>计算属性:{{ reversedMsg }}</p>
<hr>
<p>函数:{{fReversedMsg()}}</p>
<p>函数:{{fReversedMsg()}}</p>
<p>函数:{{fReversedMsg()}}</p>
</div>
<script>
// 计算属性的特点:缓存
// - 如果计算属性所依赖的数据项并没有发生变化,则就算使用多个计算函数,其函数也只执行一次
// 因为它把结果缓存起来了。
{
data() {
return { msg: 'javascript' }
},
methods: {
updateMsg () {
this.msg = "abc"
// 由于计算属性有缓存,虽然在页面上用到三次,但它的函数体只执行一次。
// 对于普通的函数,在页面上用到了三次,它就会执行三次
},
fReversedMsg () {
console.log( '函数 fReversedMsg' )
//把msg的翻转一下
let newMsg = this.msg.split('').reverse().join('')
return newMsg
}
},
computed: {
reversedMsg () {
console.log( 'reversedMsg' )
//把msg的翻转一下
let newMsg = this.msg.split('').reverse().join('')
return newMsg
}
}
})
</script>
小结
- 计算属性有缓存,提高渲染性能。
- 如果在页面上需要用到 对现有的数据进行加工得到新数据,则时要使用计算属性
案例-品牌管理(总价和均价)
目标
基于之前的案例, 完成总价和均价的计算效果
代码
<tr style="background-color: #EEE">
<td>统计:</td>
<td colspan="2">总价钱为: {{ allPrice }}</td>
<td colspan="2">平均价: {{ svgPrice }}</td>
</tr>
<tfoot v-if="list.length == 0">
<tr>
<td colspan="5" style="text-align: center">暂无数据</td>
</tr>
</tfoot>
<script>
export default {
// ...源代码省略
computed: {
allPrice(){
return Math.floor(this.list.reduce((sum, obj) => sum += obj.price, 0))
},
svgPrice(){
return Math.floor(this.allPrice / this.list.length)
}
}
}
</script>
总结: 总价来源于所有数据计算而来的结果, 故采用计算属性
计算属性-完整写法(难点-了解)
目标
计算属性也是变量, 如果想要直接赋值, 需要使用完整写法=>开启读写模式
语法
computed: {
"属性名": {
set(值){
},
get() {
return "值"
}
}
}
需求
- 计算属性给v-model使用
页面准备输入框
<template>
<div>
<div>
<span>名字:</span>
<input type="text" v-model="full">
</div>
</div>
</template>
<script>
export default {
data () {
return {
msg: 'full'
}
},
computed: {
full: {
get(){ // 获取full的值
console.log("get方法触发");
return this.msg
},
set(val){ // 要给full赋值
console.log(val)
this.msg = val
}
}
}
}
</script>
小结
想要给计算属性赋值, 需要使用set方法
案例-全选和反选
完成全选和反选的功能
注意: 小选框都选中(手选/点反选), 全选自动选中
- 写方法实现
- 计算属性实现
图示:
素材
<template>
<div>
<span>全选:</span>
<input type="checkbox" />
<button >反选</button>
<ul>
<li >
<input type="checkbox" />
<span>名字</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
arr: [
{
name: "猪八戒",
checked: false,
},
{
name: "孙悟空",
checked: false,
},
{
name: "唐僧",
checked: false,
},
{
name: "白龙马",
checked: false,
},
],
};
}
};
</script>
<style>
</style>
正确答案:
<template>
<div>
<span>全选:</span>
<input
type="checkbox"
v-model="isAll"
/>
<button @click="fan">反选</button>
<ul>
<li
v-for="(item, index) in arr"
:key="index"
>
<input
type="checkbox"
v-model="item['checked']"
/>
<span>{{ item["name"] }}</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
arr: [
{
name: "猪八戒",
checked: false,
},
{
name: "孙悟空",
checked: false,
},
{
name: "唐僧",
checked: false,
},
{
name: "白龙马",
checked: false,
},
],
}
},
methods: {
// 方法实现
fan () {
this.arr.forEach((obj) => {
obj.checked = !obj["checked"]
})
},
},
computed: {
// 计算属性实现
isAll: {
set (val) {
// 设置isAll的值的时候触发此方法, 传入要设置的值
// val是全选框的true/false的值
this.arr.forEach((obj) => {
obj["checked"] = val
})
},
get () {
return this.arr.every((obj) => obj["checked"] === true)
},
},
// isAll () {
// return this.arr.every((obj) => obj["checked"] === true)
// }
},
};
</script>
<style>
</style>
过滤器
目标:
- 理解过滤器的作用和使用场景
- 掌握定义和使用过滤器。
对金额和时间做格式化
作用
过滤器的作用:转换格式, 把数据在显示之前做格式转换
格式
定义的格式
{
data(){},
computed:{},
methods:{},
// 定义过滤器
filters: {
// 属性名称(过滤器名称):属性的值(过滤器处理函数)
myFilter:function(value,其它参数){
return 过滤后的结果
}
}
}
使用的格式
// 不带参数
{{ msg | 过滤器}}
// 带参数
{{ msg | 过滤器(参数)}}
示例:带参数的过滤器
把时间戳转成年-月-日格式
filters: {
// 过滤器的定义
// 属性名称(过滤器名称):属性的值(过滤器处理函数)
// myFilter: function(value,其它参数) {
// }
fFormatDate: function (val) {
console.log('val', val)
// val 就是需要被过滤器处理的值
// return '你被过滤了' + val
const dt = new Date(val)
return dt.getFullYear() + '-' + (dt.getMonth()+1) + '-' + dt.getDate()
}
}
调用:
日期:{{ timeStamp | fFormatDate}},
注意:
- 它的工作过程就是函数的调用执行过程。
- 过滤器本质是一个函数:它的接收的参数是格式化之前的数据及格式化的参数,它的返回值是格式化之间的值
小结
过滤器使用场景: 对于拿到的数据在显示到页面的过程中,如果发现格式不是我们想要的,可以通过过滤器去转下格式。它一定需要入参,入参表示要转格式的数据。
计算属性:对于拿到的数据进行加工,以得到新的数据项。它不需要入参,因为它需要的数据在函数内部都可以通过this.XXX来获取到。
在vue3中已经不再支持过滤器了!
vue监听器-基本使用(重点)
作用
侦听器/监听器
可以监听数据(data/computed等)的值的改变。 数据的值有类型:基本数据类型,引用数据类型
语法
data(){},
computed:{},
methods:{},
filters:{},
watch: {
"被监听的属性名" (newVal, oldVal){
}
}
代码
<template>
<div>
<input type="text" v-model="name">
</div>
</template>
<script>
export default {
data(){
return {
name: ""
}
},
watch: {
name (newVal, oldVal){ // 当msg变量的值改变触发此函数
console.log(newVal, oldVal);
}
}
}
</script>
<style>
</style>
小结
想要监听一个属性变化, 可使用监听属性watch
监听属性-深度监听和立即执行
目标
监听复杂类型, 或者立即执行监听函数
语法
watch: {
"要监听的属性名": {
immediate: true, // 立即执行
deep: true, // 深度监听复杂类型内变化
handler (newVal, oldVal) {
}
}
}
示例
<template>
<div>
<input type="text" v-model="user.name">
<input type="text" v-model="user.age">
</div>
</template>
<script>
export default {
data(){
return {
user: {
name: "小白",
age: 18
}
}
},
watch: { // 固定属性(设置监听哪些属性)
user: { // 具体属性名(被监听)
handler(newVal, oldVal){ // 固定触发此函数
console.log(newVal);
},
immediate: true, // 马上监听触发
deep: true // 深度监听(监听name和age值的改变)
}
}
}
</script>
小结
很重要 : immediate立即监听, deep深度监听, handler固定方法触发
案例-品牌管理(数据缓存)
目标
监听list变化, 同步到浏览器本地
需求
- 品牌数据缓存到本地=> 新增和修改价格都支持保存到本地
- 刷新后可以从本地读取渲染,上次缓存数据
<script>
export default {
data() {
return {
name: "", // 名称
price: 0, // 价格
list: JSON.parse(localStorage.getItem('data')) || []
};
},
methods: {
hDel(index) {
// 删除数组中指定位置的元素
this.list.splice(index, 1);
},
hAdd() {
// 收集用户的输入信息
// 简单判空
if (this.name.length == 0 || this.price.length == 0 || this.price < 0) {
alert("请写入正确的名字和价格");
return; // 阻止代码继续向下执行-返回出去这个函数
}
let id = this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100
this.list.push({
id,
name: this.name,
price: this.price,
time: new Date()
});
},
},
watch: {
list: {
handler(newArr){
localStorage.setItem('data', JSON.stringify(newArr))
},
deep: true
}
}
};
</script>
总结
- v-for能监测到哪些数组方法变化, 更新页面(响应式)=》
- 调用数组方法(push、splice可以修改原数组,就可以触发刷新)
- 数组下标修改列表的值(不会触发响应式)=>解=》
this.$set(数组, 数组的索引, 数组修改的值)
- key的作用是什么 =》给v-for遍历的元素标记唯一值
- 虚拟dom和diff算法作用 =》修改了变量=》会生成一份最新的虚拟DOM=》通过diff算法和上一次虚拟DOM=》找不同=》只更新变化部分
- 动态设置class或style=》通过data变量动态控制样式
- vue过滤器作用和分类 =》作用:格式化data中定义的变量数据=》不影响原变量的值
- vue计算属性作用=》新的变量的定义方式=》用法和data中定义的变量一样 =>{{计算属性函数名}}
- vue监听器的作用
总结, 当计算属性函数里引用的vue变量发生改变, 函数就执行并重新返回结果并缓存起来