0
点赞
收藏
分享

微信扫一扫

java中常见的锁策略

m逆光生长 2024-04-15 阅读 9
  • 1. 能够了解更新监测, key作用, 虚拟DOM, diff算法
  • 2. 能够掌握设置动态样式
  • 3. 能够掌握过滤器, 计算属性, 侦听器
  • 4. 能够完成品牌管理案例

一.Vue基础_更新监测和key

1.v-for更新监测 

 目标:目标结构变化, 触发v-for的更新 

  • 情况1: 数组翻转
  • 情况2: 数组截取
  • 情况3: 更新值

 口诀:

数组变更方法, 就会导致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更新问题,如下: 

2.v-for就地更新  

 目标:当数组改变后是如何更新的

旧-虚拟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>

 3.真实DOM

目标:在document对象上, 渲染到浏览器上显示的标签 

虚拟DOM  

目标:本质是保存节点信息, 属性和内容的一个JS对象 ,真实DOM属性过多, 遍历耗时

 

目标:在内存中比较变化部分, 然后给真实DOM打补丁(更新)

  1. 内存中生成一样的虚拟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'
      }
    }
  2. 以后vue数据更新

    • 生成新的虚拟DOM结构

    • 和旧的虚拟DOM结构对比

    • 利用diff算法, 找不不同, 只更新变化的部分(重绘/回流)到页面 - 也叫打补丁

==好处1: 提高了更新DOM的性能(不用把页面全删除重新渲染)==

==好处2: 虚拟DOM只包含必要的属性(没有真实DOM上百个属性)==

3.diff算法  

目标:同级比较-根元素变化-整个dom树删除重建  

旧虚拟DOM

<div id="box">
   <p class="my_p">123</p>
</div>

新虚拟DOM

<ul id="box">
   <li class="my_p">123</li>
</ul>
情况2: 根元素没变, 属性改变, ==元素复用==, 更新属性

旧虚拟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算法

4.无key 

目标:从第二个往后更新内容 – 性能不高

 情况3: 根元素没变, 子元素没变, 元素内容改变
无key - 就地更新

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属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素

目标:先产生新旧虚拟DOM, 根据key比较, 还是就地更新  

有key, 值唯一不重复的字符串或数字

目标:有key属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素

  • 给每个数据换成对象, 准备id, 把id的值作为key  

有key, 值为id

目标:先产生新旧虚拟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>

 5.动态class

目标: 用v-bind给标签class设置动态的值

  • 语法 :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>

6.动态style  

目标: 给标签动态设置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>

7.案例-品牌管理(铺)  

  • 需求1: 把默认数据显示到表格上
  • 需求2: 注意资产超过100的, 都用红色字体标记出来  

  • ① 先铺设静态页面 --- 去.md文档里, 复制数据和标签模板
  • ② 此案例使用bootstrap, 需要下载, 并导入到工程main.js中
  • ③ 用v-for配合默认数据, 把数据默认铺设到表格上显示
  • ④ 直接在标签上, 大于100价格, 动态设置red类名

 首先使用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>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="价格" />
                    </div>
                </div>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <!-- 阻止表单提交 -->
                <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>

8.案例-品牌管理(增)

品牌数据增加, 功能实现

  • 需求1: 实现表单数据新增进表格功能
  • 需求2: 判断用户输入是否为空给提示

分析

  • ① 添加资产按钮 – 绑定点击事件
  • ② 给表单v-model绑定vue变量收集用户输入内容
  • ③ 添加数组到数组中
  • ④ 判断用户内容是否符合规定
<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>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="价格" v-model="price" />
                    </div>
                </div>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <!-- 阻止表单提交(刷新网页数据又回去了) -->
                <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>

9.案例-品牌管理(删)  

需求1: 点击删除的a标签, 删除数据

需求2: 删除没数据了要提示暂无数据的tfoot

  • ① a标签绑定点击事件
  • ② 给事件方法传id
  • ③ 通过id, 找到对应数据删除
  • ④ 删除光了要让tfoot显示
  • ⑤ 删除光了再新增, 有bug(id值问题)需要修复
<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>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="价格" v-model.number="price" />
                    </div>
                </div>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <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>

 二.Vue基础_过滤器

1.过滤器_定义使用

目标: 转换格式, 过滤器就是一个函数, 传入值返回处理后的值

过滤器只能用在, 插值表达式和v-bind动态属性里

Vue中的过滤器场景

  • 字符串翻转, "输入hello, world", 输出"dlrow ,olleh”
  • 字母转大写, 输入"hello", 输出"HELLO”

语法:

  • Vue.filter("过滤器名", (值) => {return "返回处理后的值"})
  • filters: {过滤器名字: (值) => {return "返回处理后的值"}

<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>

第三个是鼠标悬浮的时候会出现翻转 

2.过滤器_传参和多过滤器  

目标: 可同时使用多个过滤器, 或者给过滤器传参

语法:

  • 过滤器传参: vue变量 | 过滤器(实参)
  • 多个过滤器: vue变量 | 过滤器1 | 过滤器2

<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>

 点击第三个会出现右图所出现的

 

3.案例-品牌管理(时间格式化) 

 需求: 表格里的时间用过滤器+moment模块, 格式化成YYYY-MM-DD 格式

  • ① 下载moment模块到当前工程
  • ② 定义过滤器, 传入时间, 用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>
        &nbsp;&nbsp;&nbsp;&nbsp;
        <div class="form-group">
          <div class="input-group">
            <input
              type="text"
              class="form-control"
              placeholder="价格"
              v-model.number="price"
            />
          </div>
        </div>
        &nbsp;&nbsp;&nbsp;&nbsp;
      
        <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基础_计算属性

1.计算属性_computed  

目标: 一个变量的值, 依赖另外一些数据计算而来的结果

注意: 计算属性也是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>

 

2.计算属性_缓存  

目标: 计算属性, 基于依赖项的值进行缓存,依赖的变量不变, 都直接从缓存取结果

 

<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>

3.案例-品牌管理(总价和均价)  

完成总价和均价的显示结果

需求: 完成商品总价和均价的数据显示功能

分析:

  • ① tbody最后新增一行tr
  • ② 定义总价和均价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>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="价格" v-model.number="price" />
                    </div>
                </div>
                &nbsp;&nbsp;&nbsp;&nbsp;

                <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>

4.计算属性_完整写法

目标: 计算属性也是变量

 

网页输入的值无法传到后端上 

 

<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>

 

5.案例-小选影响全选  

 需求: 小选框都选中(手选), 全选自动选中

分析:

  • ① 先静态后动态, 从.md拿到静态标签和数据
  • ② 循环生成复选框和文字, 对象的c属性和小选框的选中状态, 用v-model双向绑定
  • ③ 定义isAll计算属性, 值通过小选框们统计c属性状态得来

 

6.案例-全选影响小选  

  • 需求1: 获取到全选状态 – 改装isAll计算属性
  • 需求2: 全选状态同步给所有小选框  

分析:

  • ①: isAll改成完整写法, set里获取到全选框, 勾选的状态值
  • ②: 遍历数据数组, 赋给所有小选框v-model关联的属性

7.案例-反选  

需求: 点击反选, 让所有小选框, 各自取相反勾选状态

分析:

  • ①: 小选框的勾选状态, 在对象的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>

 

四.Vue基础_侦听器

1.侦听器_watch

 目标: 可以侦听data/computed属性值的改变

2.侦听器_深度侦听和立即执行  

目标: 侦听复杂类型, 或者立即执行侦听函数

 

 

举报

相关推荐

0 条评论