赞
踩
目标:目标结构变化, 触发v-for的更新
口诀:
数组变更方法, 就会导致v-for更新, 页面更新
push
方法是 JavaScript 数组对象的一个方法,用于向数组的末尾添加一个或多个新元素,并返回添加新元素后数组的新长度 pop
方法是 JavaScript 数组对象的一个方法,用于移除数组的最后一个元素,并返回被移除的元素。shift
方法是 JavaScript 数组对象的一个方法,用于移除数组的第一个元素,并返回被移除的元素。unshift
方法是 JavaScript 数组对象的一个方法,用于向数组的开头添加一个或多个新元素,并返回添加新元素后数组的新长度。splice
方法是 JavaScript 数组对象的一个方法,用于在指定位置插入或删除元素,并返回被删除的元素组成的数组。sort
方法是 JavaScript 数组对象的一个方法,用于对数组的元素进行排序。默认情况下,sort
方法会将数组的元素转换为字符串,然后按照 Unicode 码点顺序进行排序。reverse
方法是 JavaScript 数组对象的一个方法,用于颠倒数组中元素的顺序,即将数组中的元素从后向前排列。数组非变更方法, 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set()
filter
方法可以帮助程序员方便地对数组进行筛选,从而得到符合特定条件的元素集合。新建一个文件夹,用vscode打开文件,在用命令vue create demo创建项目
- <template>
- <div>
- <ul>
- <li v-for="(val,index) in arr" :key="index">{{ val }}</li>
- </ul>
- <button @click="revBtn">数组翻转</button>
- <button @click="sliceBtn">截取前三个</button>
- <button @click="updateBtn">点击改掉第一个元素的值</button>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- arr: [5,3,9,2,1]
- }
- },
- methods: {
- revBtn(){
- // 1.数据翻转可以让v-for更新
- this.arr.reverse()
- },
- sliceBtn(){
- // 2.数组slice方法不会造成v-for更新
- // slice不会改变原始数组
- this.arr.slice(0,3)
- // console.log(re)
-
- // 解决v-for更新 ---覆盖原始数组
- let newArr = this.arr.slice(0,3)
- this.arr = newArr
- },
- updateBtn(){
- // 3.更新某个值的时候,v-for是监测不到的
- // this.arr[0] = 1000;
-
- // 解决-This.$set()
- // 参数1:更新目标结构
- // 参数2:更新位置
- // 参数3:更新值
- this.$set(this.arr,0,1000)
- }
- }
- }
- </script>
-
- <style>
-
- </style>
在截取前三个问题中,如何解决v-for更新,如下图:
在点击改掉第一个元素的值中,如何解决v-for更新问题,如下:
1. 哪些数组方法会导致v-for更新页面?
可以改变原数组的方法
2. 有的数组方法不导致v-for更新页面, 如何处理?
拿返回的新数组, 直接替换旧数组 this.$set()方法更新某个值
目标:当数组改变后是如何更新的
旧-虚拟DOM结构: 新-虚拟DOM结构:
新旧DOM产生后对比, 然后决定是否复用真实DOM/更新内容
- <template>
- <div>
- <ul>
- <li v-for="(val, ind) in arr" :key="ind">{{ val }}</li>
- </ul>
- <button @click="btn">下标1位置插入新来的</button>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- arr: ["老大","老二","老三"]
- }
- },
- methods: {
- btn(){
- this.arr.splice(1,0,'新来的')
- }
- }
- }
- </script>
-
- <style>
-
- </style>
v-for更新时, 是如何操作DOM的?
循环出新的虚拟DOM结构, 和旧的虚拟DOM
结构对比, 尝试复用标签就地更新内容
目标:在document对象上, 渲染到浏览器上显示的标签
目标:本质是保存节点信息, 属性和内容的一个JS对象 ,真实DOM属性过多, 遍历耗时
目标:在内存中比较变化部分, 然后给真实DOM打补丁(更新)
内存中生成一样的虚拟DOM结构(==本质是个JS对象==)
因为真实的DOM属性好几百个, 没办法快速的知道哪个属性改变了
比如template里标签结构
- <template>
- <div id="box">
- <p class="my_p">123</p>
- </div>
- </template>
对应的虚拟DOM结构
- const dom = {
- type: 'div',
- attributes: [{id: 'box'}],
- children: {
- type: 'p',
- attributes: [{class: 'my_p'}],
- text: '123'
- }
- }
以后vue数据更新
生成新的虚拟DOM结构
和旧的虚拟DOM结构对比
利用diff算法, 找不不同, 只更新变化的部分(重绘/回流)到页面 - 也叫打补丁
==好处1: 提高了更新DOM的性能(不用把页面全删除重新渲染)==
==好处2: 虚拟DOM只包含必要的属性(没有真实DOM上百个属性)==
1. 虚拟DOM是什么?
本质就是一个JS对象, 保存DOM关键信息
2. 虚拟DOM好处?
提高DOM更新的性能, 不频繁操作真实DOM,
在内存中找到变化部分, 再更新真实DOM(打补丁)
目标:同级比较-根元素变化-整个dom树删除重建
旧虚拟DOM
- <div id="box">
- <p class="my_p">123</p>
- </div>
新虚拟DOM
- <ul id="box">
- <li class="my_p">123</li>
- </ul>
旧虚拟DOM
- <div id="box">
- <p class="my_p">123</p>
- </div>
新虚拟DOM
- <div id="myBox" title="标题">
- <p class="my_p">123</p>
- </div>
01、第一章webpack+vue基础/1-20 虚拟DOM+Diff算法
1. diff算法如何比较新旧虚拟DOM? 同级比较
2. 根元素变化? 删除重新建立整个DOM树
3. 根元素未变, 属性改变? DOM复用, 只更新属性
目标:从第二个往后更新内容 – 性能不高
v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key
来提供一个排序提示
- <ul id="myUL">
- <li v-for="str in arr">
- {{ str }}
- <input type="text">
- </li>
- </ul>
- <button @click="addFn">下标为1的位置新增一个</button>
- export default {
- data(){
- return {
- arr: ["老大", "新来的", "老二", "老三"]
- }
- },
- methods: {
- addFn(){
- this.arr.splice(1, 0, '新来的')
- }
- }
- };
目标:最大限度尝试就地修改/复用相同类型元素
目标:有key属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素
目标:先产生新旧虚拟DOM, 根据key比较, 还是就地更新
目标:有key属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素
目标:先产生新旧虚拟DOM, 根据key比较
key的值只能是唯一不重复的, 字符串或数值
v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key
来提供一个排序提示
新DOM里数据的key存在, 去旧的虚拟DOM结构里找到key标记的标签, 复用标签
新DOM里数据的key存在, 去旧的虚拟DOM结构里没有找到key标签的标签, 创建
旧DOM结构的key, 在新的DOM结构里没有了, 则==移除key所在的标签==
- <template>
- <div>
- <ul>
- <li v-for="obj in arr" :key="obj.id">
- {{ obj.name }}
- <input type="text">
- </li>
- </ul>
- <button @click="btn">下标1位置插入新来的</button>
- </div>
- </template>
-
- <script>
- export default {
- data() {
- return {
- arr: [
- {
- name: '老大',
- id: 50
- },
- {
- name: '老二',
- id: 31
- },
- {
- name: '老三',
- id: 10
- }
- ],
- };
- },
- methods: {
- btn(){
- this.arr.splice(1, 0, {
- id: 19,
- name: '新来的'
- })
- }
- }
- };
- </script>
-
- <style>
- </style>
1. 子元素或者内容改变会分diff哪2种情况比较?
无key, 就地更新
有key, 按照key比较
2. key值要求是?
唯一不重复的字符串或者数值
3. key应该怎么用?
有id用id, 无id用索引
4. key的好处? 可以配合虚拟DOM提高更新的性能
v-for什么时候会更新页面呢?
数组采用更新方法, 才导致v-for更新页面
vue是如何提高更新性能的?
采用虚拟DOM+diff算法提高更新性能
虚拟DOM是什么?
本质是保存dom关键信息的JS对象
diff算法如何比较新旧虚拟DOM?根元素改变 – 删除当前DOM树重新建
根元素未变, 属性改变 – 更新属性
根元素未变, 子元素/内容改变
无key – 就地更新 / 有key – 按key比较
目标: 用v-bind给标签class设置动态的值
- <template>
- <div>
- <!-- 语法:
- :class="{类名:布尔值}"
- 使用场景:vue变量控制标签是否应该有类名-->
- <p :class="{red_str: bool}">动态class</p>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- bool : true
- }
- },
- methods: {
-
- }
- }
- </script>
-
- <style scoped>
- .red_str{
- color: red;
- }
- </style>
如何给标签class属性动态赋值?
:class=“{类名: 布尔值}”, true使用, false不用
目标: 给标签动态设置style的值
语法 :style="{css属性名: 值}"
- <template>
- <div>
- <!-- 动态stule语法
- :style="{css属性名: 值}" -->
- <!-- backgroundColor是一个变量 -->
- <!-- <p :style="{backgroundColor: 'red'}">动态class</p> -->
- <p :style="{ backgroundColor: color }">动态class</p>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- color : 'red'
- }
- },
- methods: {
-
- }
- }
- </script>
-
- <style>
-
- </style>
给style赋值和class区别是?
:class="{类名: 布尔值}”, true使用, false不用
:style="{css属性名: 值}"
用到了哪些技术点?
布局用bootstrap, yarn下载引入使用
v-for把数据渲染到表格里
:class动态判断价格给红色类名
首先使用npm install bootstrap命令下载bootstrap
在main.js中引入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 v-for="obj in list" :key="obj.id">
- <td>{{ obj.id }}</td>
- <td>{{ obj.name }}</td>
-
- <!-- 如果价格超过100,就有red这个类 -->
- <td :class="{ 'red': obj.price > 100 }">{{ obj.price }}</td>
- <td>{{ obj.time }}</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>
- // 1. 明确需求
- // 2. 标签+样式+默认数据
- // 3. 下载bootstrap, main.js引入bootstrap.css
- // 4. 把list数组 - 铺设表格
- // 5. 修改价格颜色
- 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">
- <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 v-for="obj in list" :key="obj.id">
- <td>{{ obj.id }}</td>
- <td>{{ obj.name }}</td>
-
- <!-- 如果价格超过100,就有red这个类 -->
- <td :class="{ 'red': obj.price > 100 }">{{ obj.price }}</td>
- <td>{{ obj.time }}</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="资产名称" v-model="name"/>
- </div>
- </div>
-
- <div class="form-group">
- <div class="input-group">
- <input type="text" class="form-control" placeholder="价格" v-model="price" />
- </div>
- </div>
-
- <!-- 阻止表单提交(刷新网页数据又回去了) -->
- <button class="btn btn-primary" @click.prevent="addFn">添加资产</button>
- </form>
- </div>
- </div>
- </template>
-
- <script>
- // 目标:新增
- // 1.按钮 - 事件
- // 2.给表单v-model绑定vue变量
- 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') }
- ],
- };
- },
- methods:{
- addFn(){
- // 5.判断是否为空
- if (this.name.trim().length == 0 || this.price === 0){
- alert('不能为空')
- return
- }
- // 3.把值以对象形式-插入list
- this.list.push({
- // 当前数组最后一个对象的id+1作为新对象id值
- id: this.list[this.list.length - 1] .id +1,
- name: this.name,
- price: this.price,
- time:new Date()
- })
- }
- }
-
- };
- </script>
-
- <style >
- .red {
- color: red;
- }
- </style>
涉及到了哪些技术点?
@绑定事件
v-model收集表单数据
.prevent阻止按钮提交表单刷新页面
v-model修饰符 数组取最后一个元素
需求1: 点击删除的a标签, 删除数据
需求2: 删除没数据了要提示暂无数据的tfoot
- <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 v-for="obj in list" :key="obj.id">
- <td>{{ obj.id }}</td>
- <td>{{ obj.name }}</td>
-
- <!-- 如果价格超过100,就有red这个类 -->
- <td :class="{ red: obj.price > 100 }">{{ obj.price }}</td>
- <td>{{ obj.time }}</td>
- <td><a href="#" @click="delFn(obj.id)">删除</a></td>
- </tr>
- </tbody>
- <tfoot v-show="list.length === 0">
- <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="资产名称" v-model="name" />
- </div>
- </div>
-
- <div class="form-group">
- <div class="input-group">
- <input type="text" class="form-control" placeholder="价格" v-model.number="price" />
- </div>
- </div>
-
- <button class="btn btn-primary" @click.prevent="addFn">添加资产</button>
- </form>
- </div>
- </div>
- </template>
-
- <script>
- // 目标: 删除功能
- // 1. 删除a标签-点击事件
- // 2. 对应方法名
- // 3. 数据id到事件方法中
- // 4. 通过id, 找到这条数据在数组中的下标
- // 5. splice方法删除原数组里的对应元素
- // 6. 设置tfoot, 无数据给出提示
- // 7. 无数据再新增, id要判断一下
- 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') }
- ],
- };
- },
- methods: {
- addFn() {
- if (this.name.trim().length === 0 || this.price === 0) {
- alert("不能为空")
- return
- }
-
- // 解决bug: 无数组新增-list没有数据, id需要给一个固定值(以后id都是后台生成, 现在是模拟给一个id)
- let id = this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100
-
- this.list.push({
- // 当前数组最后一个对象的id+1作为新对象id值
- id: id,
- name: this.name,
- price: this.price,
- time: new Date()
- })
- },
- delFn(id) {
- // 通过id找到这条数据在数组中下标
- let index = this.list.findIndex(obj => obj.id === id)
- this.list.splice(index, 1)
- }
- }
- };
- </script>
-
- <style >
- .red {
- color: red;
- }
- </style>
涉及到了哪些技术点?
事件传id
删除数组元素方法
id值判断问题
目标: 转换格式, 过滤器就是一个函数, 传入值返回处理后的值
过滤器只能用在, 插值表达式和v-bind动态属性里
Vue中的过滤器场景
语法:
- <template>
- <div>
- <p>原来的样子:{{ msg }}</p>
- <!-- 2.过滤器使用
- 语法: {{ 值 | 过滤器名字 }} -->
- <p>使用翻转过滤器: {{ msg | reverse }}</p>
- <p :title="msg | toUp">鼠标长度</p>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- msg: 'Hello, Vue'
- }
- },
- // 方式2:局部 - 过滤器
- // 只能在当前vue文件内使用
- /*
- 语法:
- filters:{
- 过滤器名字(val){
- return 处理后的值
- }
- }
- */
- filters:{
- toUp(val){
- return val.toUpperCase()
- }
- }
- }
- </script>
-
- <style>
-
- </style>
第三个是鼠标悬浮的时候会出现翻转
1. Vue中过滤器作用?
传入一个值, 处理后返回另外一个值
2. 如何定义过滤器?
main.js – Vue.filter('过滤器名字', 函数体)
某.vue文件 – filters: {'过滤器名字': 函数体}
3. 如何使用过滤器? Vue变量 | 过滤器名字
4. 过滤器注意事项? 插值表达式 / 动态属性
目标: 可同时使用多个过滤器, 或者给过滤器传参
语法:
- <template>
- <div>
- <p>原来的样子:{{ msg }}</p>
- <!-- 1.给过滤器传参
- 语法:vue变量 | 过滤器名(值)
- -->
- <p>使用翻转过滤器: {{ msg | reverse('|') }}</p>
- <!-- 2.
- 多个过滤利使用
- 语法:vue变量 | 过滤器1 | 过滤器2 -->
- <p :title="msg | toUp | reverse('|')">鼠标长度</p>
- </div>
- </template>
-
- <script>
- export default {
- data() {
- return {
- msg: 'Hello, Vue'
- }
- },
- filters: {
- toUp(val) {
- return val.toUpperCase()
- }
- }
- }
- </script>
-
- <style></style>
点击第三个会出现右图所出现的
1. 多个过滤器使用?
vue变量 | 过滤器1 | 过滤器2
2. 如何给过滤器传额外值
vue变量 | 过滤器(值)
需求: 表格里的时间用过滤器+moment模块, 格式化成YYYY-MM-DD 格式
涉及到了哪些技术点?
yarn下包
过滤器定义和使用
moment复习
先使用npm install moment 下载moment
在main.js中引入moment
- <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 v-for="obj in list" :key="obj.id">
- <td>{{ obj.id }}</td>
- <td>{{ obj.name }}</td>
-
- <!-- 如果价格超过100,就有red这个类 -->
- <td :class="{red: obj.price > 100}">{{ obj.price }}</td>
- <!-- 3. 使用过滤器 -->
- <td>{{ obj.time | formatDate }}</td>
- <td><a href="#" @click="delFn(obj.id)">删除</a></td>
- </tr>
- </tbody>
- <tfoot v-show="list.length === 0">
- <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="资产名称"
- v-model="name"
- />
- </div>
- </div>
-
- <div class="form-group">
- <div class="input-group">
- <input
- type="text"
- class="form-control"
- placeholder="价格"
- v-model.number="price"
- />
- </div>
- </div>
-
-
- <button class="btn btn-primary" @click.prevent="addFn">添加资产</button>
- </form>
- </div>
- </div>
- </template>
-
- <script>
- // 目标: 处理时间
- // 1. 下载moment模块
- import moment from 'moment'
-
- 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') }
- ],
- };
- },
- methods: {
- addFn(){
- if (this.name.trim().length === 0 || this.price === 0) {
- alert("不能为空")
- return
- }
-
- // 解决bug: 无数组新增-list没有数据, id需要给一个固定值(以后id都是后台生成, 现在是模拟给一个id)
- let id = this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100
-
- this.list.push({
- // 当前数组最后一个对象的id+1作为新对象id值
- id: id,
- name: this.name,
- price: this.price,
- time: new Date()
- })
- },
- delFn(id){
- // 通过id找到这条数据在数组中下标
- let index = this.list.findIndex(obj => obj.id === id)
- this.list.splice(index, 1)
- }
- },
- // 2. 定义过滤器, 编写内部代码
- filters: {
- formatDate (val){
- return moment(val).format('YYYY-MM-DD')
- }
- }
- };
- </script>
-
- <style >
- .red{
- color: red;
- }
- </style>
目标: 一个变量的值, 依赖另外一些数据计算而来的结果
注意: 计算属性也是vue数据变量, 所以不要和data里重名, 用法和data相同
- <template>
- <div>
- <p>{{ num }}</p>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- a: 10,
- b: 20
- }
- },
- // 计算属性
- // 场景:一个变量的值,需要用另外变量计算而得来
- /*
- 语法:
- computed:{
- 计算属性名(){
- retturn 值
- }
- }
- */
- computed:{
- num(){
- return this.a + this.b
- }
- }
- }
- </script>
-
- <style>
-
- </style>
1. 计算属性使用场景?
当变量的值, 需要通过别人计算而得来
2. 计算属性特点?
函数内使用的变量改变, 重新计算结果返回
3. 计算属性注意事项?
计算属性名和data里名字不能重复
目标: 计算属性, 基于依赖项的值进行缓存,依赖的变量不变, 都直接从缓存取结果
- <template>
- <div>
- <p>{{ reverseMessage }}</p>
- <p>{{ reverseMessage }}</p>
- <p>{{ reverseMessage }}</p>
- <p>{{ getMessage() }}</p>
- <p>{{ getMessage() }}</p>
- <p>{{ getMessage() }}</p>
- </div>
- </template>
-
- <script>
- export default {
- data(){
- return {
- msg: "Hello, Vue"
- }
- },
- // 计算属性优势:
- // 带缓存
- // 计算属性对应函数执行后,会把return值缓存起来
- // 依赖项不变,多次调用都是从缓存取值
- // 依赖项值-变化,函数会"自动"重新执行-并缓存新的值
- computed:{
- reverseMessage(){
- console.log("计算属性执行了")
- return this.msg.split("").reverse().join("")
- }
- },
- methods: {
- getMessage(){
- console.log("函数执行了")
- return this.msg.split("").reverse().join("")
- }
- }
- }
- </script>
-
- <style>
-
- </style>
1. 计算属性好处是?
带缓存
依赖项不变, 直接从缓存取
依赖项改变, 函数自动执行并重新缓存
2. 计算属性使用场景?
当变量值, 依赖其他变量计算而得来才用
完成总价和均价的显示结果
需求: 完成商品总价和均价的数据显示功能
分析:
- <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 v-for="obj in list" :key="obj.id">
- <td>{{ obj.id }}</td>
- <td>{{ obj.name }}</td>
-
- <!-- 如果价格超过100,就有red这个类 -->
- <td :class="{ red: obj.price > 100 }">{{ obj.price }}</td>
-
- <td>{{ obj.time | formatDate }}</td>
- <td><a href="#" @click="delFn(obj.id)">删除</a></td>
- </tr>
- <tr style="background-color: #eee">
- <td>统计:</td>
- <td colspan="2">总价钱为: {{ allPrice }}</td>
- <td colspan="2">平均价: {{ avgPrice }}</td>
- </tr>
- </tbody>
- <tfoot v-show="list.length === 0">
- <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="资产名称" v-model="name" />
- </div>
- </div>
-
- <div class="form-group">
- <div class="input-group">
- <input type="text" class="form-control" placeholder="价格" v-model.number="price" />
- </div>
- </div>
-
-
- <button class="btn btn-primary" @click.prevent="addFn">添加资产</button>
- </form>
- </div>
- </div>
- </template>
-
- <script>
- // 目标: 总价和均价显示
- // 1. 末尾补tr - 显示总价和均价
- import moment from 'moment'
- 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') }
- ],
- };
- },
- methods: {
- addFn() {
- if (this.name.trim().length === 0 || this.price === 0) {
- alert("不能为空")
- return
- }
-
- // 解决bug: 无数组新增-list没有数据, id需要给一个固定值(以后id都是后台生成, 现在是模拟给一个id)
- let id = this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100
-
- this.list.push({
- // 当前数组最后一个对象的id+1作为新对象id值
- id: id,
- name: this.name,
- price: this.price,
- time: new Date()
- })
- },
- delFn(id) {
- // 通过id找到这条数据在数组中下标
- let index = this.list.findIndex(obj => obj.id === id)
- this.list.splice(index, 1)
- }
- },
- filters: {
- formatDate(val) {
- return moment(val).format("YYYY-MM-DD");
- },
- },
- // 2. 计算属性
- computed: {
- allPrice() {
- // 3. 求总价
- return this.list.reduce((sum, obj) => sum += obj.price, 0)
- },
- avgPrice() {
- // 4. 求均价 - 保留2位小数
- return (this.allPrice / this.list.length).toFixed(2)
- }
- }
- };
- </script>
-
- <style >
- .red {
- color: red;
- }
- </style>
涉及到的知识点?
computed定义和使用计算属性
数组reduce方法累积运算
目标: 计算属性也是变量
网页输入的值无法传到后端上
- <template>
- <div>
- <span>姓名:</span>
- <input type="text" v-model="full">
- </div>
- </template>
-
- <script>
- // 问题:给计算属性赋值 - 需要setter
- // 解决:
- /*
- 完整语法:
- computed:{
- "计算属性名" (){},
- "计算属性名":{
- set(值){
- },
- get(){
- return 值
- }
- }
- }
- */
- export default {
- data(){
- return {
-
- }
- },
- computed:{
- full:{
- // 给full赋值触发set方法
- set(val){
- console.log(val);
- },
- // 使用full赋值触发get方法
- get(){
- return "无名氏"
- }
- }
- }
- }
- </script>
-
- <style>
-
- </style>
1. 何时用计算属性完整写法?
给计算属性变量赋值时
2. set函数和get函数什么执行?
set接收要赋予的值
get里要返回给这个计算属性具体值
需求: 小选框都选中(手选), 全选自动选中
分析:
小选框如何影响全选框选中状态的?
v-model给全选框绑定isAll计算属性
isAll计算属性里返回统计小选框选中状态结果
分析:
全选如何影响小选框选中状态的?
小选框v-model, 关联数组里对象的c属性
isAll计算属性的set方法, 拿到全选框状态
状态值赋给, 数组里每个对象的c属性
需求: 点击反选, 让所有小选框, 各自取相反勾选状态
分析:
反选如何实现的? 遍历每个对象, 把c属性的值取反再赋予回去
- <template>
- <div>
- <span>全选:</span>
- <!-- 4. v-model 关联全选 - 选中状态 -->
- <input type="checkbox" v-model="isAll" />
- <button @click="btn">反选</button>
- <ul>
- <li v-for="(obj, index) in arr" :key="index">
- <!-- 3. 对象.c - 关联 选中状态 -->
- <input type="checkbox" v-model="obj.c" />
- <span>{{ obj.name }}</span>
- </li>
- </ul>
- </div>
- </template>
-
- <script>
- // 目标: 小选框 -> 全选
- // 1. 标签+样式+js准备好
- // 2. 把数据循环展示到页面上
- export default {
- data() {
- return {
- arr: [
- {
- name: "猪八戒",
- c: false,
- },
- {
- name: "孙悟空",
- c: false,
- },
- {
- name: "唐僧",
- c: false,
- },
- {
- name: "白龙马",
- c: false,
- },
- ],
- };
- },
- // 5. 计算属性-isAll
- computed: {
- isAll: {
- set(val) {
- // 7. 全选框 - 选中状态(true/false)
- this.arr.forEach(obj => obj.c = val)
- },
- get() {
- // 6. 统计小选框状态 -> 全选状态
- // every口诀: 查找数组里"不符合"条件, 直接原地返回false
- return this.arr.every(obj => obj.c === true)
- }
- }
- },
- methods: {
- btn() {
- // 8. 让数组里对象的c属性取反再赋予回去
- this.arr.forEach(obj => obj.c = !obj.c)
- }
- }
- };
- </script>
-
- <style></style>
目标: 可以侦听data/computed属性值的改变
如何侦听到某个变量值改变呢? 使用watch配置项, key是要侦听的data/计算属性名
目标: 侦听复杂类型, 或者立即执行侦听函数
1. 如何侦听一个对象/数组呢? 把侦听器写成对象形式, 给handler方法和deep:true
2. 侦听器函数马上执行? immediate: true
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。