part4 - 模块1 - 04 - Vue进阶语法

226 阅读6分钟

笔记来源:拉勾教育 - 大前端就业集训营

文章内容:学习过程中的笔记、感悟、和经验

Vue进阶语法

自定义指令

官方文档:cn.vuejs.org/v2/guide/cu…

指令用于简化Dom操作,相当于对基础Dom操作的一种封装

当我们希望使用一些内置指令不具备的Dom操作功能时,可以进行自定义指令的设置

自定义全局指令

可以被任意Vue实例或者组建使用的指令,也就是说哪怕我们new了多个Vue实例,这些实例都可以使用全局自定义指令

Vue提供了directive方法可以进行自定义指令的创建

<body>
  <div id="app">
    <!-- 在元素上使用自定义全局指令cwn,控制台输出 ‘我插入dom中了’ -->
    <!-- 注意,使用自定义前面加v- -->
    <p v-cwn>123</p>
    <!-- 设置标签diaplay为none,,控制台输出 ‘我插入dom中了’ -->
    <p v-cwn style="display: none;">123</p>
    <!-- 设置标签v-if使标签不会被插入到页面中,控制台没哟输出任何内容,表示如果标签不能真正的插入到Dom中的话,上面的自定义指令并不会执行 -->
    <p v-cwn style="display: none;" v-if="value === 0">123</p>
  </div>
  <script>
    //  使用Vue的directive方法创建自定义指令
    // 参数1:表示自定义指令名
    // 参数2:配置项
    Vue.directive('cwn', {
      //inserted表示标签插入Dom中后执行的函数
      //element是当前设置了自定义指令的元素本身,所以我们可以在函数中对元素做一些操作
      //banding表示element上面的一些信息
      inserted: function (element,banding) {
        console.log('我插入dom中了')
        // 打印元素看一下
        console.log(element)
      }
    })
    const vm = new Vue({
      el: '#app',
      data: {
        value: ''
      }
    })
  </script>
</body>

注意:inserted只是一个钩子函数,directive的第二个参数内部可以写多个钩子函数

自定义局部指令

只能在当前Vue实例或者组建内部使用的指令

自定义局部指令和全局指令使用方法很相似

<body>
  <div id="app">
    <!-- 在元素上使用自定义局部指令cwn,控制台输出 ‘我插入dom中了’ -->
    <!-- 注意,使用自定义前面加v- -->
    <p v-cwn>123</p>
    <!-- 设置标签diaplay为none,,控制台输出 ‘我插入dom中了’ -->
    <p v-cwn style="display: none;">123</p>
    <!-- 设置标签v-if使标签不会被插入到页面中,控制台没哟输出任何内容,表示如果标签不能真正的插入到Dom中的话,上面的自定义指令并不会执行 -->
    <p v-cwn style="display: none;" v-if="value === 0">123</p>
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        value: ''
      },
      // directives内部可以设置自定义局部指令
      directives: {
        // cwn是指令名,指令名的值是一个对象
        cwn: {
          // 对象内部全部都是钩子函数,可以有多个
          // inserted表示当标签插入Dom中执行
          inserted(element) {
            console.log('我插入dom中了')
            console.log(element)
          }
        }
      }
    })
  </script>
</body>

注意:局部指令不能再vue实例之外的位置使用

过滤器

用于进行文本内容格式化处理的工具

可以在差值表达式和v-bind中使用

全局过滤器

可以在任何Vue实例中使用

// 书写方法
Vue.filter( 过滤器名称 , function(value){ 
// 逻辑代码
return 处理结果
})

使用方法:在差值表达式和v-bind中使用管道符号“|”连接数据

<body>
  <div id="app">
    <!-- 使用过滤器filterId和filterContent,使用管道符|连接 -->
    <p :id="id | filterId">123</p>
    <p>{{ content | filterContent }}</p>
  </div>
  <script>
    // 设置全局过滤器,
    // 参数1:过滤器名称
    // 参数2:过滤器执行函数,解构一个参数value为要处理的数据
    Vue.filter('filterId', function (value) {
      // 我们在这里拼接字符
      return '我是id' + value
    })
    Vue.filter('filterContent', function (value) {
      return '我是Content' + value
    })
    const vm = new Vue({
      el: '#app',
      data: {
        id: '123',
        content: '文本内容'
      }
    })
  </script>
</body>

注意:过滤器最后只能使用return出来的结果,如果不写return则输出为空

全局过滤器特殊用法

  • Vue中允许数据传入到多个过滤器中进行处理,后一个过滤器使用的value是前一个过滤器返回值

    • 例如:<p :id="id | filterId | filterContent">123</p>
  • 一个过滤器传入多个参数,参数也可以在过滤器中使用,注意value始终都是是第一个值,后面新传入的参数向后顺延

    • <!-- 过滤器filterId再传入两个参数 -->
      <p :id="id | filterId(10, 'hello')">123</p>
      
      // 过滤器使用参数
      Vue.filter('filterId', function (value, x, y) {
        // 我们在这里拼接字符
        return value + x + y
      })
      

局部过滤器

只能在当前Vue实例中使用的过滤器

// 书写方法:书写在Vue实例中
filters: {
  // 过滤器名称:函数
  filterContent: function (value) {
    // 逻辑代码
    return 处理结果
  }
}
<body>
  <div id="app">
    <!-- 调用局部过滤器 -->
    <p>{{ content | filterA }}</p>
    <p>{{ content | filterB }}</p>
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        id: '123',
        content: '文本内容'
      },
      // filters里面书写局部过滤器,只能在当前vue实例中使用
      filters: {
        // 过滤器可以按照过滤器名:函数的方式书写
        filterA: function (value) {
          return '我是过滤器A' + value
        },
        // 也可以直接简写为一个函数
        filterB(value) {
          return '我是过滤器B' + value
        },
      }
    })
  </script>
</body>

和全局过滤器一样,局部也可以使用多个过滤器处理一个数据,同样也可以传入多个参数

过滤器注意事项

如果同时存在全局过滤器和局部过滤器并且同名的时候,Vue优先使用局部过滤器

计算属性

  • Vue视图(HTML)中不建议书写复杂的逻辑,不利于维护
  • 封装函数是很好的方式,但是有时可能会重复计算消耗不必要的资源
  • 计算数属性使用时为属性的形式,第一次访问时会自动触发内部函数,并把结果保存下来以供下次使用,后续再次调用都会检查依赖的数据是否发生变化,如果发生变化会再次执行,否则会直接使用当前存储的结果
<body>
  <div id="app">
    <!-- 使用计算属性 -->
    <p>{{ sum }}</p>
    <!-- 后面再次使用计算属性会先判断arr是否发生变化,如果没有变化直接使用上次的结果 -->
    <!-- 下面两次调用在控制台可以看到没有打印‘我执行了’,证明下面两次调用没有再次执行计算属性 -->
    <p>{{ sum }}</p>
    <p>{{ sum }}</p>
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        arr: [1, 2, 3, 4]
      },
      // computed内部书写计算属性
      computed: {
        // 可以按照函数的方法书写,sum为计算属性名,
        sum() {
          // 在每次执行计算属性之前都输出一下‘我执行了’
          console.log('我执行了')
          let he = 0
          let arr = this.arr
          for (const i of arr) {
            he += i
          }
          return he
        }
      }
    })
  </script>
</body>

计算属性-computed和函数-methods的区别

  • 计算属性具有缓存性,函数没有
  • 计算属性通过属性名访问,函数需要调用
  • 计算属性仅仅适用于计算操作

案例

需求:数组元素大于10时创建li,否则不创建

解决方法:

  • v-if和v-for结合
  • v-for和methods结合
  • v-for和计算属性结合(最优解
<body>
  <div id="app">
    <!-- 利用计算属性动态创建结构 -->
    <ul>
      <!-- v-for使用计算属性fn结果 -->
      <li v-for="item in fn" :key="item">{{ item }}</li>
      <!-- 后续再次使用的时候也调用fn,就可直接使用newArr -->
      <li v-for="item in fn" :key="item">{{ item }}</li>
      <li v-for="item in fn" :key="item">{{ item }}</li>
      <li v-for="item in fn" :key="item">{{ item }}</li>
    </ul>
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        arr: [1, 11, 2, 22, 3, 33, 4, 44, 5, 55]
      },
      computed: {
        // 计算属性
        fn() {
          // 使用数组筛选方法,筛选全部大于10的数据
          return this.arr.filter(item => item > 10)
        }
      }
    })
  </script>
</body>

计算属性的setter

计算属性默认只有getter。vue允许给计算属性设置setter进行一些数据的更新(一般情况下,使用getter的方式比较多)

<body>
  <div id="app">
    <!-- 使用计算属性 -->
    <p>{{sun}}</p>
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        // 设置三个字符串存储名字
        x: '张',
        y: '三',
        z: ''
      },
      computed: {
        // 计算属性完整写法
        sun: {
          // get - 默认用法,使用会直接执行get
          get() {
            return this.x + this.y + this.z
          },
          // set - 修改数据,当我们在程序中修改sun的值的时候(vm.sun='韩梅梅')会触发这个方法,然后会再次调用get渲染
          set(value) {
            const newArr = value.split('')
            this.x = newArr[0]
            this.y = newArr[1]
            this.z = newArr[2]
          }
        }
      }
    })
  </script>
</body>

侦听器

用于监听数据变化,并执行指定操作

<body>
  <div id="app">
    <!-- 侦听器 -->
    <input type="text" v-model="value">
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        value: ''
      },
      // watch内部书写侦听器
      watch: {
        // 侦听value变化,接收两个值,新值和旧值,一旦发生数据变化执行结构体
        value(newvalue, oldvalue) {
          console.log('侦听器执行了', newvalue, oldvalue)
        }
      }
    })
  </script>
</body>

监听对象数据

如果我们直接修改对象赋值,那么上面的方法是可以生效的,但是如果我们更改对象内部内部成员,就需要使用下面的方法

监听对象内部值变化,需要将侦听器书写为一个对象,内部书写deep:true,在通过gandler设置处理函数

<body>
  <div id="app">
    <!-- 侦听器 -->
    <input type="text" v-model="value">
  </div>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        value: '',
        obj: {
          name: 'zs',
          age: 16
        }
      },
      // watch内部书写侦听器
      watch: {
        // 侦听value变化,接收两个值,新值和旧值,一旦发生数据变化执行结构体
        value(newvalue, oldvalue) {
          console.log('侦听器执行了', newvalue, oldvalue)
        },
        obj: {
          // 监听对象内部成员变化
          deep: true,
          handler(val, oldval) {
            //val, oldval 是相同的,他们指向同一个物内存位置
            console.log('侦听器执行了', val, oldval)
          }
        }
      }
    })
  </script>
</body>

注意事项

  • 当我们更改(非替换)数组或者对象时,回调函数中的新值和旧值是相同的,因为此时他们指向同一个位置
  • 数组不需要使用deep: true设置,所以使用第一种方法就可以了(注意vue中数组处理不可以使用索引和legth操作)

Vue DevTools

vue官方提供的用来调试Vue应用的工具 - 一款谷歌浏览器插件,直接在谷歌扩展商店搜索即可

地址(需要科学上网):chrome.google.com/webstore/de…

注意事项

  • 网页必须应用的Vue才能看到Vue DevTools
  • 使用的vue必须是Vue.js而不是vue.min.js
  • 需要使用HTTP协议打开,不可以使用file(右键运行)的方式打开

使用方法

打开开发者工具F12,找到Vue即可使用,会看到一个操作面板,其中的root点击可以查看到当前实例的数据

Vue生命周期

Vue实例的生命周期,从vue实力创建到运行再到销毁的过程

官方文档:cn.vuejs.org/v2/guide/in…

生命周期函数/钩子:可以在特定生命周期阶段执行特定的功能

创建阶段

  1. 初始化阶段
    1. beforeCreate:实例在初始化之前调用,一般不用,此时data、函数都没有创建完毕
    2. created:实例创建之后调用,比较常用,此时data、函数都已经创建并可使用了
  2. 挂载阶段
    1. beforeMount:实例挂载前调用
    2. mounted:实例挂载之后调用,已经可以进行Dom操作了(比较常用)

注意:创建阶段函数只能执行一次

运行阶段

  1. beforeUpdata:数据更新后,实体更新前调用,此时视图还没有更新,访问只能获取更新前的视图数据
  2. updated:视图更新后调用

注意:此阶段按需调用,每个阶段的函数都可以执行多次

销毁阶段

  1. beforeDestroy:实例销毁之前调用,此时实例还没有销毁,内部的数据等还能访问
  2. destroyed:实例销毁之后调用,此时已经不存在实例的,也无法访问了