Vue3总结中.......

135 阅读4分钟

vue3

模板语法

1、动态参数

<!-- 动态参数 -->
<!-- 如果你的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定就等价于 v-bind:href -->
<a :[a.href]="a.url">百度一下</a><!-- 自定义绑定事件名 -->
<a @[eventName]="doSomething">{{ count }}点击加1</a>
​
data () {
    return {
        rawHtml: '<span style="color: red">This should be red.</span>',
        href: 'href',
        a: {
            href: 'href',
            url: 'http://www.baidu.com'
        },
        eventName: 'click'
    };
},
​
methods: {
    doSomething() {
        console.log(1)
    }
}

响应式基础

1、reactive()

<template>
  <div>
     <div>{{ state.count }}</div>
     <button @click="addCount">点击count累加</button>
  </div>
</template>
 
<script setup>
import { reactive } from 'vue';
​
export default {
   setup() {
     // 利用reactive设置响应式数据
     const state = reactive({ count: 0 })
​
     // 使count++的函数
     function addCount() {
       state.count++
     }
​
     // 暴露state,addCount
     return {
       state,
       addCount
     }
  }
}
</script>

2、<script setup>

  • setup() 函数中手动暴露大量的状态和方法非常繁琐。幸运的是,我们可以通过使用构建工具来简化该操作。当使用单文件组件(SFC)时,我们可以使用 <script setup> 来大幅度地简化代码。

  • 备注:什么是单文件组件

    • 在 Vue 应用中,提供了 .vue 为后缀的文件,我们将这类的文件,称之为“单文件组件”,也就是说,每一个文件,都是一个单独的组件。(其实我们平时每个.vue文件都是单文件组件
  • 单文件组件写法

  • <template>
      <div>
         <div>{{ state.count }}</div>
         <button @click="addCount">点击count累加</button>
      </div>
    </template>
     
    <script setup>
      import { reactive } from 'vue';
      // 利用reactive设置响应式数据
      const state = reactive({ count: 0 })
    ​
      // 使count++的函数
      function addCount() {
        state.count++
      }
    ​
    </script><style scoped lang='less'>
         
    </style>
    

3、reactive()的局限性

  • 仅对对象类型有效(对象、数组和 Map、Set这样的集合类型),而对 stringnumberboolean 这样的 原始类型无效。
  • 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失:
  • <template>
      <div>
         <div>{{ state.count }}</div>
         <button @click="countValue(count)">点击触发函数</button>
      </div>
    </template>
     
    <script setup>
      import { reactive } from "vue";
    ​
      /**
       * 因为 Vue 的响应式系统是通过属性访问进行追踪的,
       * 因此我们必须始终保持对该响应式对象的相同引用。
       * 这意味着我们不可以随意地“替换”一个响应式对象,
       * 因为这将导致对初始引用的响应性连接丢失:
       */
      // let state = reactive({ count: 0 })
      // state = reactive({ count: 1 })
    ​
      let state = reactive({ count: 0 })
      // 此处的n不是响应式的
      let n = state.count
      n++
      // count也不是响应式的
      let { count } = state
      count++
    ​
      function countValue(count) {
        const a = state.count++
        console.log('解构后的count,失去了响应式', count)
        console.log('响应式count', a)
      }
    ​
    ​
    </script>
    

4、ref()

  • 允许创建可以使用任何值类型的响应式 ref
  • <template>
      <div>
        <!-- 模板中使用不需要加value -->
        <div>ref定义响应式(简单): {{ count }}</div>
        <div>ref定义响应式(复杂):{{ countObj }}</div>
        <button @click="addCount">+1</button>
      </div>
    </template>
     
    <script setup>
      import { ref } from "vue";
      // 简单数据类型设置响应式
      let count = ref(100)
      let countObj = ref({ count: 1 })
      let obj = {
        foo: ref(1)
      }
      
      // foo是解构出来的,但也是响应式的
      const { foo } = obj
      
      function addCount() {
          
        count.value++
        countObj.value.count++
        obj.foo.value++
        console.log(countObj.value, foo.value)
      }
    </script><style scoped lang='less'>
         
    </style>
    

5、响应性语法糖(待总结)

计算属性

  • computed()`方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 publishedBooksMessage.value访问计算结果。
  • 计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
  • <template>
      <div>
        <p>Has published books:</p>
        <!-- 不使用计算属性时 -->
        <div>{{ author.books.length > 0 ? 'Yes' : 'No' }}</div>
        <!-- 使用计算属性时 -->
        <div>{{ publishedBooksMessage }}</div>
        <button @click="changeComputed">尝试修改计算属性</button>
         <!-- 可修改的计算属性 -->
        <div>你的名字是: {{ fullName }}</div>
      </div>
    </template>
     
    <script setup>
    import { computed, reactive, ref } from 'vue'
    const author = reactive({
      name: 'John Doe',
      books: [
        'Vue 2 - Advanced Guide',
        'Vue 3 - Basic Guide',
        'Vue 4 - The Mystery'
      ]
    })
    // 计算属性
    let publishedBooksMessage = computed(() => {
      return author.books.length > 0 ? 'Yes' : 'No'
    })
    ​
    ​
    const firstName = ref('John')
    const lastName = ref('Doe')
    ​
    const fullName = computed({
      // getter
      get() {
        return firstName.value + ' ' + lastName.value
      },
      // setter
      set(newValue) {
        // 注意:我们这里使用的是解构赋值语法
        [firstName.value, lastName.value] = newValue.split(' ')
      }
    })
    ​
    const changeComputed = () => {
      fullName.value = 'Xiao Fu'
    }
    </script><style scoped lang='less'>
    </style>
    

1、计算属性和方法的区别

  • 不考虑其他东西,两者可实现相同的效果,都可以去依赖其他项去计算
  • 区别在于计算属性值会基于其响应式依赖被缓存,计算属性仅会在其响应式依赖更新时才会重新计算,依赖项不变,计算属性也不会发生变化,不会去重复执行getter函数
  • 而方法总是会在重新渲染时再次执行函数,不管依赖项有没有发生改变
  • 函数形式的计算属性是只读的,当你尝试修改一个计算属性时,你会收到一个运行时警告(官网解释,但自己试了一下没有警告,但模板渲染的值没有进行更新
  • 计算属性设置为对象形式时,会有get和set方法,set方法可以对计算属性进行修改,对象形式的计算属性是可读可写的,修改之后如果模板用到这个计算属性时,也会发生相应的更新

2、总结

  • 官方建议计算属性是基于原有数据的一个派生,依赖于其他值进行变化,其他值发生变化计算属性才会跟着变化,计算属性应该是只读的,不要去直接更改它,更建议通过依赖项的改变去触发它的重新计算。

类与样式绑定

  • <template>
      <div>
        <!-- 字面量方式绑定 -->
        <div :class="{ active: isActive }">
          1111
        </div>
        <!-- 对象方式绑定 -->
        <div :class="classObject">222</div>
    ​
        <!-- 数组形式绑定 -->
        <div :class="[activeClass, errorClass]">333</div>
      </div></template>
     
    <script setup>
    import { reactive, ref } from 'vue'const isActive = ref(true)
    // 对象方式直接绑定
    const classObject = reactive({
      active: true,
      'text-danger': true
    })
    ​
    const activeClass = ref('active')
    const errorClass = ref('text-danger')
    </script><style scoped>
    .active {
      margin: 10px;
      width: 100px;
      height: 100px;
      background-color: orange;
    }
    ​
    .text-danger {
      font-size: 30px;
    }
    </style>
    

条件渲染

v-if和v-show

  • 和vue2一致

  • 两者都能控制dom元素的显隐,区别在于

    • v-if实现元素显隐的原理是DOM的创建销毁,会经历组件的创建和销毁
    • v-show实现元素显隐的原理是进行样式的控制,通过操控display: none / block进行控制,无论元素是否显示,它都会进行渲染,在显隐切换的过程中不会经历组件的创建和销毁
    • 因此来说,v-if有更高的切换开销,v-show有更高的渲染开销,当频繁进行切换时,v-show相对较好,当绑定条件很少改变时,v-if相对更加合适
  • 和vue2的区别

    • v-if和v-for同时使用时,v-if的优先级更高

      • 也就意味着v-if的条件无法访问到v-for作用域内定义的变量别名
    • 不建议两个出现在一起,造成性能的浪费

列表渲染

v-for

  • 和vue2基本一致

  • 小妙招

    • 假设有一个数组,数组每一项是数组,如果想要遍历小数组的每一项该怎么弄
    • 可以先遍历大数组,v-for的item就是每一个小数组,再遍历item,item的每一项就是小数组的每一项
    • <ul v-for="numbers in sets">
          <li v-for="n in even(numbers)">{{ n }}</li>
      </ul><script>
          const sets = ref([
            [1, 2, 3, 4, 5],
            [6, 7, 8, 9, 10]
          ])
      ​
          function even(numbers) {
            return numbers.filter((number) => number % 2 === 0)
          }
      </script>
      

事件处理

  • v-on:事件类型 / @事件类型进行触发事件执行相应的方法逻辑

  • 可以跟一个方法,也可以编写内联JavaScript代码

  • 方法没有参数时可以只写方法名,当有参数时可以(参数)进行传参处理

  • 需要访问原生dom事件时,可以传入一个特殊的$event, 或者使用内联箭头函数

  • <template>
      <div>
        <!-- 使用特殊的 $event 变量 -->
        <button @click="warn('Form cannot be submitted yet.', $event)">
          Submit
        </button>
    ​
        <!-- 使用内联箭头函数 -->
        <button @click="(event) => warn('Form cannot be submitted yet.', event)">
          Submit
        </button>
      </div>
    </template>
     
    <script setup>
    function warn(a, e) {
      console.log(a, e);
    }
    </script>
    

    暂时未写功能描述

  • 事件修饰符

    • .stop
    • .prevent
    • .self
    • .capture
    • .once
    • .passive
  • 按键修饰符

    • .enter
    • .tab
    • .delete (捕获“Delete”和“Backspace”两个按键)
    • .esc
    • .space
    • .up
    • .down
    • .left
    • .right
  • 系统按键修饰符

    • .ctrl

    • .alt

    • .shift

    • .meta

      • 当出现链式使用时,例如@keyup.ctrl.alt,它会再ctrl + alt 键弹起时触发
    • .exact:使用系统按键修饰符不跟.exact时,指定按键触发时同时按下别的键也会触发,但加上.exact后就不会触发,有且只能指定按键触发,多一个都不行

  • 鼠标按键修饰符

    • .left
    • .right
    • .middle

生命周期钩子(待定)