• ⑥ composition API


    Composition API

    1 Setup 函数的使用

    Composition api 代码编写要建立在 setup 函数上

    • 执行时间:created 实例被完全初始化之前

      • setup 函数内部 获取不到 this

    1.1 return 的内容可以在 template 中直接使用

    const app = Vue.createApp({
      template: `
       <div @click="handleClick">name: {{name}}, age: {{age}}</div>
     `,
     // created 实例被完全初始化之前
     setup(props, context) {
       return {
         name: 'dell',
         age: 18,
         handleClick() {
           alert(1223)
         }
       }
     },
    })
    const vm = app.mount('#root')
    

    1.2 setup 函数内部不能使用外部的方法;生命周期函数、方法中可以使用 setup 函数

    const app = Vue.createApp({
      template: `
        <div @click="handleClick">name: {{name}}, age: {{age}}</div>
      `,
      methods: {
        test() {
          console.log(this.$options.setup());
        }
      },
      mounted() {
        this.test()
      },
      // created 实例被完全初始化之前
      setup(props, context) {
        return {
          name: 'dell',
          age: 18,
          handleClick() {
            alert(1223)
          }
        }
      },
    })
    const vm = app.mount('#root')
    

    2 ref,reactive 响应式引用的用法和原理

    • 原理:通过 proxy 对数据进行封装,当数据变化时,触发模板等内容的更新

    2.1 ref:处理基础类型的数据

    const app = Vue.createApp({
      template: `
        <div>name: {{ name }}</div>
      `,
      setup(props, context) {
        const { ref } = Vue;
        // ref, 'dell' 变成 proxy({ value: 'dell' }) 的响应式引用
        let name = ref('dell');
        setTimeout(() => {
          name.value = 'lee'
        }, 2000);
        return { name }
      },
    })
    const vm = app.mount('#root')
    

    2.2 reactive:处理非基础类型的数据

    const app = Vue.createApp({
      template: `
        <div>name: {{ nameObj.name }}</div>
      `,
      setup(props, context) {
        const { reactive } = Vue;
        // reactive, { name: 'dell' } 变成 proxy({ name: 'dell' }) 的响应式引用
        const nameObj = reactive({ name: 'dell' });
        setTimeout(() => {
          nameObj.name = 'lee'
        }, 1000);
        return { nameObj }
      },
    })
    const vm = app.mount('#root')
    

    2.3 readonly:限制响应式引用不可被修改

    const app = Vue.createApp({
      template: `
        <div>name: {{ nameObj.name }}</div>
      `,
      setup(props, context) {
        const { reactive, readonly } = Vue;
        const nameObj = reactive({ name: 'dell' });
        const copyNameObj = readonly(nameObj);
        setTimeout(() => {
          nameObj.name = 'lee'
          copyNameObj.name = 'lee' // target is readonly.
        }, 1000);
        return { nameObj, copyNameObj}
      },
    })
    const vm = app.mount('#root')
    

    2.4 toRefs:将响应式属性的属性转换为响应式的

    const app = Vue.createApp({
      template: `
        <div>name: {{ name }}</div>
      `,
      setup(props, context) {
        const { reactive, toRefs } = Vue;
        // reactive, { name: 'dell' } 变成 proxy({ name: 'dell' }) 的响应式引用
        const nameObj = reactive({ name: 'dell', age: 18 });
        setTimeout(() => {
          nameObj.name = 'lee'
          nameObj.age = 20
        }, 1000);
        // toRefs, ({ name: 'dell', age: 18 }) 变成 { name: proxy({ value: 'dell' }), age: proxy({ value: 18 })}
        const { name } = toRefs(nameObj)
        return { name }
      },
    })
    const vm = app.mount('#root')
    

    3 toRef 以及 context 参数

    3.1 toRef

    const app = Vue.createApp({
      template: `
        <div>name: {{ age }}</div>
      `,
      setup(props, context) {
        const { reactive, toRef } = Vue;
        const data = reactive({ name: 'dell' });
        const age = toRef(data, 'age')
        setTimeout(() => {
          age.value = 'lee'
        }, 1000);
        return { age }
      },
    })
    const vm = app.mount('#root')
    

    3.2 context

    1. attrs

    • attrs -> Non-Props 属性
    const app = Vue.createApp({
      template: `
        <child app='app' />
      `,
    })
    app.component('child', {
      template: `
        <div>child</div>
      `,
      setup(props, context) {
        const { attrs, slots, emit } = context
        console.log(attrs); // Non-Props属性
        return {}
      },
    })
    const vm = app.mount('#root')
    

    2. slots

    • slots.default() -> slot的内容
    const app = Vue.createApp({
      template: `
        <child>parent</child>
      `,
    })
    app.component('child', {
      setup(props, context) {
        const { h } = Vue
        const { attrs, slots, emit } = context
        console.log(slots.default()); // slot 的内容
        return () => h('div', {}, slots.default())
      },
    })
    const vm = app.mount('#root')
    

    3. emit

    const app = Vue.createApp({
      methods: {
        handleChange() {
          alert('change')
        }
      },
      template: `
        <child @change="handleChange">parent</child>
      `,
    })
    app.component('child', {
      template: `<div @click="handleClick">123123</div>`,
      setup(props, context) {
        const { h } = Vue
        const { attrs, slots, emit } = context
        function handleClick() { emit('change') } // 向外触发事件
        return { handleClick }
      },
    })
    const vm = app.mount('#root')
    

    4 使用 Composition API 开发 TodoList

    // 关于 list 操作的代码做封装
    const listRelativeEffect = () => {
      const { reactive } = Vue;
      const list = reactive([]);
      const addItemToList = (item) => {
        list.push(item)
      }
      return { list, addItemToList }
    }
    // 关于 input 操作的代码做封装
    const inputRelativeEffect = () => {
      const { ref } = Vue;
      const inputValue = ref('');
      const handleInpulValueChange = e => {
        inputValue.value = e.target.value
      }
      return { inputValue, handleInpulValueChange }
    }
    const app = Vue.createApp({
      setup() {
        // 流程调度中转
        const { list, addItemToList } = listRelativeEffect()
        const { inputValue, handleInpulValueChange } = inputRelativeEffect()
    
        return {
          list,
          addItemToList,
          inputValue,
          handleInpulValueChange,
        }
      },
      template: `
        <div>
          <input :value="inputValue" @input="handleInpulValueChange" />
          <div>{{ inputValue }}</div>
          <button @click="()=>addItemToList(inputValue)">提交</button>
          <ul>
            <li v-for="(item, index) in list" :key=index>{{ item }}</li>
          </ul>
        </div>
      `,
    })
    const vm = app.mount('#root')
    

    5 computed方法生成计算属性

    • computed 一般操作 get
    const app = Vue.createApp({
      setup() {
        const { ref, computed } = Vue;
        const count = ref(0);
        const handleClick = () => count.value += 1
        const countAddFive = computed(() => count.value + 5 )
        return { count, handleClick, countAddFive }
      },
      template: `
        <div>
          <span @click="handleClick">{{count}}</span> -- {{countAddFive}}
        </div>
      `,
    })
    const vm = app.mount('#root')
    
    • computed 一般操作 get + set
    const app = Vue.createApp({
      setup() {
        const { ref, computed } = Vue;
        const count = ref(0);
        const handleClick = () => count.value += 1
        let countAddFive = computed({
          get: () => {
            return count.value + 5
          },
          set: (param) => {
            return count.value = param - 5
          }
        })
        setTimeout(() => {
          countAddFive.value = 100
        }, 1000);
        return { count, handleClick, countAddFive }
      },
      template: `
        <div>
          <span @click="handleClick">{{count}}</span> -- {{countAddFive}}
        </div>
      `,
    })
    const vm = app.mount('#root')
    

    6 watch 和 watchEffect 的使用和差异性

    6.1 watch 侦听器

    • 具备一定的惰性 lazy

    • 参数可以拿到原始和当前值

    1. 一般用法

    const app = Vue.createApp({
      setup() {
        const { ref, watch } = Vue
        const name = ref('dell')
        watch(name, (currentVal, prevVal) => {
          console.log(currentVal, prevVal);
        })
    
        return { name }
      },
      template: `
        <div>
          Name: <input v-model="name" />
        </div>
        <div>
          Name is {{ name }}
        </div>
      `,
    })
    const vm = app.mount('#root')
    

    2. 侦听 reactive 方法下的数据需要用箭头函数

    const app = Vue.createApp({
      setup() {
        const { reactive, watch, toRefs } = Vue
        const nameObj = reactive({ name: 'dell' })
        watch(() => nameObj.name, (currentVal, prevVal) => {
          console.log(currentVal, prevVal);
        })
    
        const { name } = toRefs(nameObj)
    
        return { name }
      },
      template: `
        <div>
          Name: <input v-model="name" />
        </div>
        <div>
          Name is {{ name }}
        </div>
      `,
    })
    const vm = app.mount('#root')
    

    3. 用一个侦听器可以侦听多个数据的变化

    const app = Vue.createApp({
      setup() {
        const { reactive, watch, toRefs} = Vue
        const nameObj = reactive({ name: 'dell', englishName: 'lee' })
    
        watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng], [prevName, prevEng]) => {
          console.log(curName, prevName, '------------', curEng, prevEng);
        })
    
        const { name, englishName } = toRefs(nameObj)
    
        return { name, englishName }
      },
      template: `
        <div>
          Name: <input v-model="name" />
        </div>
        <div>
          Name is {{ name }}
        </div>
        <div>
          englishName: <input v-model="englishName" />
        </div>
        <div>
          englishName is {{ englishName }}
        </div>
      `,
    })
    const vm = app.mount('#root')
    

    4. 设置非惰性

    watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng], [prevName, prevEng]) => {
      console.log(curName, prevName, '------------', curEng, prevEng);
    }, { immediate: true })
    

    6.2 watchEffect 侦听器,偏向于 effect

    • 立即执行,没有惰性 immediate

    • 不需要传递你要侦听的内容,会自动感知代码依赖,不需要传递很多参数,只要传递一个回调函数

    • 不能获取之前数据的值

    const app = Vue.createApp({
        setup() {
          const { reactive, watch, toRefs, watchEffect } = Vue
          const nameObj = reactive({ name: 'dell', englishName: 'lee' })
          watchEffect(() => {
            console.log(nameObj.name);
          })
          const { name, englishName } = toRefs(nameObj)
    
          return { name, englishName }
        },
        template: `
          <div>
            Name: <input v-model="name" />
          </div>
          <div>
            Name is {{ name }}
          </div>
          <div>
            englishName: <input v-model="englishName" />
          </div>
          <div>
            englishName is {{ englishName }}
          </div>
        `,
      })
      const vm = app.mount('#root')
    

    6.3 关闭侦听

    const stop = watch(name, (currentVal, prevVal) => {
      console.log(currentVal, prevVal);
      setTimeout(() => {
        stop()
      }, 5000)
    })
    
    const stop = watchEffect(() => {
      console.log(nameObj.name);
      setTimeout(() => {
        stop()
      }, 5000);
    })
    

    7 生命周期函数的新写法

    • beforeCreate, created 不存在

    • beforeMount => onBeforeMount

    • mounbted => onMounted

    • beforeUpdate => onBeforeUpdate

    • updated => onUpdated

    • beforeUnmount => onBeforeUnmount

    • unmounted => onUnmounted

    • onRenderTracked 每次渲染后重新收集响应式依赖时执行

    • onRenderTriggered 每次触发页面重新渲染时执行

    const app = Vue.createApp({
      setup() {
        const { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onRenderTracked, onRenderTriggered } = Vue;
        const name = ref('dell')
        const handleClick = () => {
          name.value = 'lee'
        }
        onBeforeMount(() => {
          console.log('onBeforeMount');
        })
        onMounted(() => {
          console.log('onMounted');
        })
        onBeforeUpdate(() => {
          console.log('onBeforeUpdate');
        })
        onUpdated(() => {
          console.log('onUpdated');
        })
        onRenderTracked(() => {
          console.log('onRenderTracked');
        })
        onRenderTriggered(() => {
          console.log('onRenderTriggered');
        }) 
        return { name, handleClick }
      },
      template: `
        <div @click="handleClick">
          {{ name }}
        </div>
      `,
    })
    const vm = app.mount('#root')
    

    8 Provide, Inject, 模版 Ref 的用法

    8.1 provide inject

    1. 父子传值

    const app = Vue.createApp({
      setup() {
        const { provide } = Vue;
        provide('name', 'dell');
        return { }
      },
      template: `
        <div>
          <child />
        </div>
      `,
    })
    app.component('child', {
      setup() {
        const { inject } = Vue;
        const name = inject('name', 'hello'); // 'hello' 为设置的默认值
        return { name }
      },
      template: `<div>{{name}}</div>`
    })
    const vm = app.mount('#root')
    

    2. 改变传递的数据

    • readonly 单向数据流,限制父组件传递的数据只能由父组件修改
    const app = Vue.createApp({
      setup() {
        const { ref, provide, readonly } = Vue;
        const name = ref('dell');
        provide('name', readonly(name));
        provide('changeName', value => {
          name.value = value
        })
        return { }
      },
      template: `
        <div>
          <child />
        </div>
      `,
    })
    app.component('child', {
      setup() {
        const { inject } = Vue;
        const name = inject('name');
        const changeName = inject('changeName')
        const handleClick = () => {
          changeName('lee')
        }
        return { name, handleClick }
      },
      template: `<div @click="handleClick">{{name}}</div>`
    })
    const vm = app.mount('#root')
    

    8.2 dom ref

    • CompositionApi 语法下获取真实的 DOM 元素节点
    const app = Vue.createApp({
      setup() {
        const { ref, onMounted } = Vue
        // ②
        const hello = ref(null);
        onMounted(() => {
          console.log(hello, hello.value);
        })
        // ③
        return { hello }
      },
      // ①
      template: `
        <div>
          <div ref="hello">hello</div>
        </div>
      `,
    })
    const vm = app.mount('#root')
    
  • 相关阅读:
    计算机网络七:中继器、集线器、交换机、路由器、网桥和网关
    vue 简易计算器
    express mongodb 连接池
    vue过度动画
    Webpack 学习笔记(0)
    git 学习笔记
    MySQL 权限笔记
    java gui笔记
    3d tranform css3
    java 多线程笔记
  • 原文地址:https://www.cnblogs.com/pleaseAnswer/p/16012147.html
Copyright © 2020-2023  润新知