vue基础+过滤器详细讲解

397 阅读5分钟

1 .Vue 基础

1.0_vue 基础 v-for 更新监测

哪些方法不会导致 v-for 更新?为什么?

  • 因为操作数组的方法,并没有修改原数组,所以 v-for 不会监测到
  • 解决方案:将新数组重新赋值给原数组

注意事项:只要原数组改变了,v-for 都会自动更新

更新数组中某个元素的时候, v-for 是监测不到的

  • 在开发时很少碰到

回流重绘

回流(重排)Reflow:元素的宽高、位置、结构等属性发生变化时,就会触发回流,Layout(布局)

重绘 Repaint:元素的颜色等信息发生变化时,会触发重绘

举例:回流就是元素几何信息发生变化触发的更新,例如:宽高、位置等信息,重绘包括所有页面重新渲染,例如颜色的改变也会触发,回流一定会触发重绘,而重绘不一定会触发回流。一般情况下,我们要尽量减少重绘和回流以提高浏览器渲染性能,具体做法:减少 DOM 操作,如果非要操作,可以借助 documentFragment,一次提交多次 DOM 操作,或者使用 MVVM 框架,例如:Vue、React、Angular 等,它们内部都有虚拟 DOM 以提高渲染性能。

回流一定会触发重绘,但重绘不一定会触发回流。

这些方法会触发数组改变, v-for 会监测到并更新页面

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

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

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

1.2v-for 就地更新

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

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

1.3 虚拟 dom

.vue 文件中的 template 里写的标签, 都是模板, 都要被 vue 处理成虚拟 DOM 对象, 才会渲染显示到真实 DOM 页面上

Vue 中的虚拟 DOM 是什么?为什么要使用虚拟 DOM?

Vue 中的虚拟 DOM 本质就是一个 JS 对象,用来保存 DOM 的关键信息。当 DOM 需要发生变化时,会进行 diff 算法对比,找到更新的部分,差异更新,可以大大提高性能,减少 DOM 操作的频率。

1.4diff 算法

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

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

情况 2: 根元素没变, 属性改变, ==元素复用==, 更新属性

1.5diff 算法-key

情况 3: 根元素没变, 子元素没变, 元素内容改变

无 key - 就地更新

v-for 不会移动 DOM, 而是尝试复用, 就地更新,如果需要 v-for 移动 DOM, 你需要用特殊 attribute key 来提供一个排序提示

1.6v-for key 属性

key 的作用

  • 提高渲染性能
  • 让数据和元素相互绑定

key 的要求

  • 唯一的字符串或数字

总结: 不用 key 也不影响功能(就地更新), 添加 key 可以提高更新的性能

举例:如果没有使用 key,会有 2 个小问题,1. v-for 会采用就地更新,性能稍弱,2.数据和结构没有关联。如果元素中有一些带状态的组件,会丢失状态。如果有 key ,v-for 更新时会比较 key ,内容会跟随元素,进一步减少 DOM 操作。key 必须设置为唯一的字符串或数字。

1.7 动态 class

  • 语法:
    • :class="{类名: 布尔值}"

1.8-动态 style

语法

  • :style="{css 属性: 值}"
<template>
  <div>
    <!-- 语法:
      :class="{类名: 布尔值}"
      使用场景: vue变量控制标签是否应该有类名
     -->
    <p :class="{ red_str: bool }">好久好久</p>
    <p :class="{ red: 1 > 0 }">好久好久</p>
    <button @click="btn">变色</button>
    <br />
    <p :style="{ color: 'red' }">就很烦</p>
    <p :style="{ color: red }">就很烦</p>
    <p :style="{ color: red, backgroundColor: 'blue' }">就很烦</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        bool: true,
        red: "red",
      };
    },
    methods: {
      btn() {
        this.bool = !this.bool;
      },
    },
  };
</script>

<style>
  .red_str {
    color: red;
  }
</style>

2.过滤器

2.1 过滤器

过滤器的应用场景?

  • **过滤器(Filters)**常用于文本的格式化,例如:日期的格式化;过滤器可以用在两个地方:插值表达式v-bind 属性绑定

使用:在插值表达式中或者 v-bind 中 语法:通过管道符链接过滤器名称,可使用多个过滤器

{
  {
    msg | reverse;
  }
}
  1. 全局过滤器 全局注册最好在 main.js 中注册, 一处注册到处使用
//一处注册到处使用
//参数一:过滤器名称
//参数二:函数
Vue.filter("reverse", (val) => val.split("").reverse().join(""));
  1. 局部过滤器 在 vue 文件中 filters 属性中定义
<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>

2.2 过滤器传参

语法:

  • 过滤器传参: vue 变量 | 过滤器(实参)
  • 多个过滤器: vue 变量 | 过滤器 1 | 过滤器 2
Vue.filter("reverse", (val, s) => val.split("").reverse().join(s));
<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",
    };
  },
  // 方式2: 局部 - 过滤器
  // 只能在当前vue文件内使用
  /*
     语法:
     filters: {
       过滤器名字 (val) {
         return 处理后的值
       }
     }
  */
  filters: {
    toUp(val) {
      return val.toUpperCase();
    },
  },
};
</script>

3vue计算属性

3.1计算属性-computed

作用:依赖其他变量计算得来的值,依赖的目标变化时会实时更新,带缓存,更新一次后会缓存起来,不会执行多次,导致性能浪费

语法:

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

用法:

<template>
  <div>
    <p>{{ num }}</p>
  </div>
</template>
<script>
export default {
  data(){
    return {
      a: 10,
      b: 20
    }
  },
     // 注意: 计算属性和data属性都是变量-不能重名
 // 注意2: 函数内变量变化, 会自动重新计算结果返回
  computed: {
    num(){
      return this.a + this.b
    }
  }
}
</script>

<style>

</style>

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

由于 v-model 会导致 computed 数据发生变化,而 computed 默认只写了 get 方法,没有 set 方法,所以会报错

语法:

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

需求:

  • 计算属性给v-model使用
<template>
  <div>
      <div>
          <span>姓名:</span>
          <input type="text" v-model="full">
      </div>
  </div>
</template>

<script>
// 问题: 给计算属性赋值 - 需要setter
// 解决:
export default {
    computed: {
        full: {
            // 给full赋值触发set方法
            set(val){
                console.log(val)
            },
            // 使用full的值触发get方法
            get(){
                return "无名氏"
            }
        }
    }
}
</script>

<style>

</style>

3.4 案例:全选反选

<template>
  <div>
    <span>全选:</span>
    <input type="checkbox" v-model="isAll" />
    <button @click="btn">反选</button>
    <ul>
      <li v-for="(obj, index) in arr" :key="index">
        <input type="checkbox" v-model="obj.c" />
        <span>{{ obj.name }}</span>
        <!-- <span>{{obj.b}}</span> -->
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: [
        {
          name: "猪八戒",
          c: false,
        },
        {
          name: "孙悟空",
          c: false,
        },
        {
          name: "唐僧",
          c: false,
        },
        {
          name: "白龙马",
          c: false,
        },
      ],
    };
  },
  methods: {
    btn() {
      this.arr.forEach((obj) => (obj.c = !obj.c));
    },
  },
  computed: {
    isAll: {
      set(val) {
        this.arr.forEach((obj) => (obj.c = val));
      },
      get() {
        // return this.arr.every((obj) => obj.c === true);
        return this.arr.every((obj) => obj.c);
      },
    },
  },
};
</script>
<style>
li {
  list-style: none;
}
</style>

4.vue侦听器

4.1侦听器-watch

作用:监听数据变化

用法:在watch中定义

语法:

watch: {
    "被侦听的属性名"(newVal, oldVal){   
        "处理业务"
    }
}

用法:

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

<script>
export default {
  data(){
    return {
      name: ""
    }
  },
  // 目标: 侦听到name值的改变

  watch: {
    // newVal: 当前最新值
    // oldVal: 上一刻值
    name(newVal, oldVal){
      console.log(newVal, oldVal);
    }
  }
}
</script>

<style>

</style>

4.2 vue侦听器-深度侦听和立即执行

深度侦听(侦听对象)

  • 语法:

    watch: {
        "要侦听的属性名": {
            immediate: true, // 立即执行
            deep: true, // 深度侦听复杂类型内变化
            //handler侦听器函数
            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: {
    user: {
      handler(newVal, oldVal){
        // user里的对象
        console.log(newVal, oldVal);
      },
      deep: true,
      immediate: true
    }
  }
}
</script>

<style>

</style>