vue基础2--vue基础API

Posted 咖啡壶子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue基础2--vue基础API相关的知识,希望对你有一定的参考价值。

1.v-for剖析

1.0 v-for更新监测

情况1: 数组翻转

情况2: 数组截取

情况3: 更新值

口诀:

数组变更方法, 就会导致v-for更新, 页面更新

数组非变更方法, 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set()

<template>
  <div>
    <ul>
      <li v-for="(val, index) in arr" :key="index">
         val 
      </li>
    </ul>
    <button @click="revBtn">数组翻转</button>
    <button @click="sliceBtn">截取前3个</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)

      // 解决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会监测到并更新页面

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

这些方法不会触发v-for更新

  • slice()
  • filter()
  • concat()

1.1 v-for就地更新

v-for 的默认行为会尝试原地修改元素而不是移动它们。

这种 虚拟DOM对比方式, 可以提高性能 - 但是还不够高

1.2 虚拟dom

.vue文件中的template里写的标签, 都是模板, 都要被vue处理成虚拟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上百个属性)

在内存中比较差异, 然后给真实DOM打补丁更新上

1.3 diff算法

vue用diff算法, 新虚拟dom, 和旧的虚拟dom比较

情况1: 根元素变了, 删除重建

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

1.4 diff算法-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, '新来的')
        
    
;

旧 - 虚拟DOM结构 和 新 - 虚拟DOM结构 对比过程

性能不高, 从第二个li往后都更新了

有key - 值为索引
  • 还是就地更新

因为新旧虚拟DOM对比, key存在就复用此标签更新内容, 如果不存在就直接建立一个新的

<ul id="myUL">
    <li v-for="(str, index) in arr" :key="index">
         str  
        <input type="text">
    </li>
</ul>
<button @click="addFn">下标为1的位置新增一个</button>
export default 
    data()
        return 
            arr: ["老大", "新来的", "老二", "老三"]
        
    ,
    methods: 
        addFn()
            this.arr.splice(1, 0, '新来的')
        
    
;

key为索引-图解过程 (又就地往后更新了)

  1. v-for先循环产生新的DOM结构, key是连续的, 和数据对应

  2. 然后比较新旧DOM结构, 找到区别, 打补丁到页面上

    最后补一个li, 然后从第二个往后, 都要更新内容

口诀: key的值有id用id, 没id用索引

有key - 值为id

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.5 vue基础 动态class

  • 语法:
    • :class="类名: 布尔值"
<template>
  <div>
    <!-- 语法:
      :class="类名: 布尔值"
      使用场景: vue变量控制标签是否应该有类名
     -->
    <p :class="red_str: bool">动态class</p>
  </div>
</template>

<script>
export default 
  data()
    return 
      bool: true
    
  

</script>

<style scoped>
  .red_str
    color: red;
  
</style>

1.6 vue基础-动态style

  • 语法
    • :style="css属性: 值"
<template>
  <div>
    <!-- 动态style语法
      :style="css属性名: 值"
     -->
    <p :style="backgroundColor: colorStr">动态style</p>
  </div>
</template>

<script>
export default 
  data()
    return 
      colorStr: 'red'
    
  

</script>

<style>

</style>

2. vue过滤器

2.0 vue过滤器-定义使用

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

过滤器只能用在, 插值表达式和v-bind表达式

Vue中的过滤器场景

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

语法:

  • 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.1 vue过滤器-传参和多过滤器

  • 语法:
    • 过滤器传参: 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. vue计算属性

3.0 vue计算属性-computed

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

语法:

  • computed: 
        "计算属性名" () 
            return "值"
        
    
    

需求:

  • 需求: 求2个数的和显示到页面上
<template>
  <div>
    <p> num </p>
  </div>
</template>

<script>
export default 
  data()
    return 
      a: 10,
      b: 20
    
  ,
  // 计算属性:
  // 场景: 一个变量的值, 需要用另外变量计算而得来
  /*
    语法:
    computed: 
      计算属性名 () 
        return 值
      
    
  */
 // 注意: 计算属性和data属性都是变量-不能重名
 // 注意2: 函数内变量变化, 会自动重新计算结果返回
  computed: 
    num()
      return this.a + this.b
    
  

</script>

<style>

</style>

3.1 vue计算属性-缓存

<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.2_vue计算属性-完整写法

语法:

computed: 
    "属性名": 
        set()
            
        ,
        get() 
            return "值"
        
    

需求:

  • 计算属性给v-model使用

页面准备输入框

<template>
  <div>
      <div>
          <span>姓名:</span>
          <input type="text" v-model="full">
      </div>
  </div>
</template>

<script>
// 问题: 给计算属性赋值 - 需要setter
// 解决:
/*
    完整语法:
    computed: 
        "计算属性名" (),
        "计算属性名": 
            set(值)

            ,
            get()
                return 值
            
        
    
*/
export default 
    computed: 
        full: 
            // 给full赋值触发set方法
            set(val)
                console.log(val)
            ,
            // 使用full的值触发get方法
            get()
                return "无名氏"
            
        
    

</script>

<style>

</style>

4. vue侦听器

4.0 vue侦听器-watch

语法:

  • watch: 
        "被侦听的属性名" (newVal, oldVal)
            
        
    
    

完整例子代码:

<template>
  <div>
    <input type="text" v-model="name">
  </div>
</template>

<script>
export default 
  data()
    return 
      name: ""
    
  ,
  // 目标: 侦听到name值的改变
  /*
  语法:
    watch: 
      变量名 (newVal, oldVal)
        // 变量名对应值改变这里自动触发
      
    
  */
  watch: 
    // newVal: 当前最新值
    // oldVal: 上一刻值
    name(newVal, oldVal)
      console.log(newVal, oldVal);
    
  

</script>

<style>

</style>

4.1_vue侦听器-深度侦听和立即执行

  • 语法:

    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: 0
      
    
  ,
  // 目标: 侦听对象
  /*
  语法:
    watch: 
      变量名 (newVal, oldVal)
        // 变量名对应值改变这里自动触发
      ,
      变量名: 
        handler(newVal, oldVal)

        ,
        deep: true, // 深度侦听(对象里面层的值改变)
        immediate: true // 立即侦听(网页打开handler执行一次)
      
    
  */
  watch: 
    user: 
      handler(newVal, oldVal)
        // user里的对象
        console.log(newVal, oldVal);
      ,
      deep: true,
      immediate: true
    
  

</script>

<style>

</style>

总结: immediate立即侦听, deep深度侦听, handler固定方法触发

以上是关于vue基础2--vue基础API的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段2——.vue文件的模板

vue3.2 基础及常用方法

VUE.js入门学习-基础精讲

Vue基础入门讲义-语法基础

vue基础 —— 单网页版的Vue学习 基础

vue基础 —— 单网页版的Vue学习 基础