• 快速掌握Vue3部分特性


      经过了漫长的迭代,Vue 3.0 终于在 2020-09-18 发布了,带了翻天覆地的变化,使用了 Typescript 进行了大规模的重构,带来了 Composition API RFC 版本,类似 React Hook 一样的写 Vue,可以自定义自己的 hook ,让使用者更加的灵活,接下来总结一下 vue 3.0 带来的部分新特性。

    一、Vue2 与 Vue3 的对比

    • 对 TypeScript 支持不友好(所有属性都放在了 this 对象上,难以推倒组件的数据类型)
    • 大量的 API 挂载在 Vue 对象的原型上,难以实现 TreeShaking。
    • 架构层面对跨平台 dom 渲染开发支持不友好
    • CompositionAPI。受 ReactHook 启发
    • 更方便的支持了 jsx
    • Vue 3 的 Template 支持多个根标签,Vue 2 不支持
    • 对虚拟 DOM 进行了重写、对模板的编译进行了优化操作...

    二、setup函数

      setup() 函数是 vue3 中,专门为组件提供的新属性。它为我们使用 vue3 的 Composition API 新特性提供了统一的入口, setup 函数会在 beforeCreate 之后、created 之前执行, vue3 也是取消了这两个钩子,统一用 setup 代替, 该函数相当于一个生命周期函数,vue 中过去的 data,methods,watch 等全部都用对应的新增 api 写在 setup()函数中

    setup(props, context) {
        context.attrs
        context.slots
        context.parent
        context.root
        context.emit
        context.refs
        return {}
      }
    • props: 用来接收 props 数据
    • context 用来定义上下文, 上下文对象中包含了一些有用的属性,这些属性在 vue 2.x 中需要通过 this 才能访问到, 在 setup() 函数中无法访问到 this,是个 undefined
    • 返回值: return {}, 返回响应式数据, 模版中需要使用的函数

    三、reactive函数

      reactive() 函数接收一个普通对象,返回一个响应式的数据对象, 想要使用创建的响应式数据也很简单,创建出来之后,在 setup 中 return 出去,直接在 template 中调用即可

    <template>
      {{name}} // test
    <template>
    
    <script lang="ts">
    import { defineComponent, reactive, ref, toRefs } from 'vue';
    export default defineComponent({
      setup(props, context) {
        let state = reactive({
          name: 'test'
        });
        return state
      }
    });
    </script>

    四、ref函数

      ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含一个 value 属性, 只在 setup 函数内部访问 ref 函数需要加.value

    <template>
        <div class="mine">
            {{count}} // 10
        </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from 'vue';
    export default defineComponent({
      setup() {
        const count = ref<number>(10)
        // 在js 中获取ref 中定义的值, 需要通过value属性
        console.log(count.value);
        return {
           count
        }
       }
    });
    </script>

      在 reactive 对象中访问 ref 创建的响应式数据

    <template>
        <div class="mine">
            {{count}} -{{t}} // 10 -100
        </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive, ref, toRefs } from 'vue';
    export default defineComponent({
      setup() {
        const count = ref<number>(10)
        const obj = reactive({
          t: 100,
          count
        })
        // 通过reactive 来获取ref 的值时,不需要使用.value属性
        console.log(obj.count);
        return {
           ...toRefs(obj)
        }
       }
    });
    </script>

      isRef() 函数用来判断某个值是否为 ref() 创建出来的对象

      setup(props, context) {
        const name: string = 'vue'
        const age = ref<number>(18)
        console.log(isRef(age)); // true
        console.log(isRef(name)); // false
        return {
          age,
          name
        }
      }

      toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据

    五、computed()

      该函数用来创造计算属性,和过去一样,它返回的值是一个 ref 对象。里面可以传方法,或者一个对象,对象中包含 set()、get()方法

    1、创建只读的计算属性

    import { computed, defineComponent, ref } from 'vue';
    export default defineComponent({
      setup(props, context) {
        const age = ref(18)
        // 根据 age 的值,创建一个响应式的计算属性 readOnlyAge,它会根据依赖的 ref 自动计算并返回一个新的 ref
        const readOnlyAge = computed(() => age.value++) // 19
        return {
          age,
          readOnlyAge
        }
      }
    });

    2、通过 set()、get()方法创建一个可读可写的计算属性

    import { computed, defineComponent, ref } from 'vue';
    export default defineComponent({
      setup(props, context) {
        const age = ref<number>(18)
        const computedAge = computed({
          get: () => age.value + 1,
          set: value => age.value + value
        })
        // 为计算属性赋值的操作,会触发 set 函数, 触发 set 函数后,age 的值会被更新
        age.value = 100
        return {
          age,
          computedAge
        }
      }
    });

    六、 watch() 函数

      watch 函数用来侦听特定的数据源,并在回调函数中执行副作用。默认情况是懒执行的,也就是说仅在侦听的源数据变更时才执行回调。

    1、监听用 reactive 声明的数据源

    <script lang="ts">
    import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
    interface Person {
      name: string,
      age: number
    }
    export default defineComponent({
      setup(props, context) {
        const state = reactive<Person>({ name: 'vue', age: 10 })
        watch(
          () => state.age,
          (age, preAge) => {
            console.log(age); // 100
            console.log(preAge); // 10
          }
        )
        // 修改age 时会触发watch 的回调, 打印变更前后的值
        state.age = 100
        return {
          ...toRefs(state)
        }
      }
    });
    </script>

    2、监听用 ref 声明的数据源

    <script lang="ts">
    import { defineComponent, ref, watch } from 'vue';
    interface Person {
      name: string,
      age: number
    }
    export default defineComponent({
      setup(props, context) {
        const age = ref<number>(10);
    
        watch(age, () => console.log(age.value)); // 100
    
        // 修改age 时会触发watch 的回调, 打印变更后的值
        age.value = 100
        return {
          age
        }
      }
    });
    </script>

    3、同时监听多个值

    <script lang="ts">
    import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
    interface Person {
      name: string,
      age: number
    }
    export default defineComponent({
      setup(props, context) {
        const state = reactive<Person>({ name: 'vue', age: 10 })
    
        watch(
          [() => state.age, () => state.name],
          ([newName, newAge], [oldName, oldAge]) => {
            console.log(newName);
            console.log(newAge);
            console.log(oldName);
            console.log(oldAge);
          }
        )
        // 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
        state.age = 100
        state.name = 'vue3'
        return {
          ...toRefs(state)
        }
      }
    });
    </script>

    4、stop 停止监听

      在 setup() 函数内创建的 watch 监视,会在当前组件被销毁的时候自动停止。如果想要明确地停止某个监视,可以调用 watch() 函数的返回值即可,语法如下

    import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
    interface Person {
      name: string,
      age: number
    }
    export default defineComponent({
      setup(props, context) {
        const state = reactive<Person>({ name: 'vue', age: 10 })
    
        const stop =  watch(
          [() => state.age, () => state.name],
          ([newName, newAge], [oldName, oldAge]) => {
            console.log(newName);
            console.log(newAge);
    
            console.log(oldName);
            console.log(oldAge);
          }
        )
        // 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
        state.age = 100
        state.name = 'vue3'
    
        setTimeout(()=> {
          stop()
          // 此时修改时, 不会触发watch 回调
          state.age = 1000
          state.name = 'vue3-'
        }, 1000) // 1秒之后讲取消watch的监听
    
        return {
          ...toRefs(state)
        }
      }
    });

    七、新的生命周期函数

      新版的生命周期函数,可以按需导入到组件中,且只能在 setup() 函数中使用, 但是也可以在 setup 外定义, 在 setup 中使用

    import { defineComponent, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onErrorCaptured, onMounted, onUnmounted, onUpdated } from 'vue';
    export default defineComponent({
      setup(props, context) {
        onBeforeMount(()=> {
          console.log('beformounted!')
        })
        onMounted(() => {
          console.log('mounted!')
        })
        onBeforeUpdate(()=> {
          console.log('beforupdated!')
        })
        onUpdated(() => {
          console.log('updated!')
        })
        onBeforeUnmount(()=> {
          console.log('beforunmounted!')
        })
        onUnmounted(() => {
          console.log('unmounted!')
        })
        onErrorCaptured(()=> {
          console.log('errorCaptured!')
        })
        return {}
      }
    });

    八、Template refs

      通过 refs 来回去真实 dom 元素, 这个和 react 的用法一样,为了获得对模板内元素或组件实例的引用,我们可以像往常一样在 setup()中声明一个 ref 并返回它

    1、还是跟往常一样,在 html 中写入 ref 的名称

    2、在steup 中定义一个 ref,然后在 steup 中返回 ref的实例

    3、onMounted 中可以得到 ref的RefImpl的对象, 通过.value 获取真实dom

    <template>
      <!--第一步:还是跟往常一样,在 html 中写入 ref 的名称-->
      <div class="mine" ref="elmRefs">
        <span>1111</span>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, onMounted, ref } from 'vue';
    export default defineComponent({
      setup(props, context) {
        // 获取真实dom
        const elmRefs = ref<null | HTMLElement>(null);
        onMounted (() => {
          console.log(elmRefs.value); // 得到一个 RefImpl 的对象, 通过 .value 访问到数据
        })
        return {
          elmRefs
        }
      }
    });
    </script>

    九、vue 的全局配置

      通过 vue 实例上 config 来配置,包含 Vue 应用程序全局配置的对象。您可以在挂载应用程序之前修改下面列出的属性:

    const app = Vue.createApp({})
    app.config = {...}

      为组件渲染功能和观察程序期间的未捕获错误分配处理程序。错误和应用程序实例将调用处理程序

    app.config.errorHandler = (err, vm, info) => {}

      可以在应用程序内的任何组件实例中访问的全局属性,组件的属性将具有优先权。这可以代替 Vue 2.xVue.prototype 扩展:

    app.config.globalProperties.$http = 'xxxxxxxxs'

      可以在组件用通过 getCurrentInstance() 来获取全局 globalProperties 中配置的信息,getCurrentInstance 方法获取当前组件的实例,然后通过 ctx 属性获得当前上下文,这样我们就能在 setup 中使用 router 和 vuex,通过这个属性我们就可以操作变量、全局属性、组件属性等等

    setup( ) {
      const { ctx } = getCurrentInstance();
      ctx.$http
    }

    十、vue 3.x 完整组件模版结构

       一个完整的 vue 3.x 完整组件模版结构包含了:组件名称、 props、components、setup(hooks、computed、watch、methods 等)

    <template>
      <div class="mine" ref="elmRefs">
        <span>{{name}}</span>
        <br>
        <span>{{count}}</span>
        <div>
          <button @click="handleClick">测试按钮</button>
        </div>
    
        <ul>
          <li v-for="item in list" :key="item.id">{{item.name}}</li>
        </ul>
      </div>
    </template>
    
    <script lang="ts">
    import { computed, defineComponent, getCurrentInstance, onMounted, PropType, reactive, ref, toRefs } from 'vue';
    
    interface IState {
      count: 0,
      name: string,
      list: Array<object>
    }
    
    export default defineComponent({
      name: 'demo',
      // 父组件传子组件参数
      props: {
        name: {
          type: String as PropType<null | ''>,
          default: 'vue3.x'
        },
        list: {
          type: Array as PropType<object[]>,
          default: () => []
        }
      },
      components: {
        /// TODO 组件注册
      },
      emits: ["emits-name"], // 为了提示作用
      setup (props, context) {
        console.log(props.name)
        console.log(props.list)
    
    
        const state = reactive<IState>({
          name: 'vue 3.0 组件',
          count: 0,
          list: [
            {
              name: 'vue',
              id: 1
            },
            {
              name: 'vuex',
              id: 2
            }
          ]
        })
    
        const a = computed(() => state.name)
    
        onMounted(() => {
    
        })
    
        function handleClick () {
          state.count ++
          // 调用父组件的方法
          context.emit('emits-name', state.count)
        }
    
        return {
          ...toRefs(state),
          handleClick
        }
      }
    });
    </script>

      这样简单介绍了解下,使用的时候再深入研究学习。

  • 相关阅读:
    NJU 操作系统实验三
    Oracle数据库的下载安装和配置
    实模式/保护模式
    FAT12
    FAT12 img tool
    Mysql InnoDB 数据更新/删除导致锁表
    程序员,你总要有点自己的想法吧!
    支付系统安全设计思维导图
    从实时清分手续费记账看代码的易读性
    (7/8)借助枚举说一下数据类型定义规范
  • 原文地址:https://www.cnblogs.com/goloving/p/13968349.html
Copyright © 2020-2023  润新知