vue3学习15mixin和compositionAPI

59 阅读3分钟

认识Mixin

组件和组件之间有时会存在相同的代码逻辑,可以使用mixin对相同代码逻辑进行抽取。

编写一个mixin.js文件

export const demoMixin = {
  data() {
    return {
      message: 'helloworld'
    }
  },
  methods: {
    foo() {
      console.log('执行mixin')
    }
  }
}

在要使用的组件中引入

import {demoMixin} from './mixins/demoMixin'
export default {
  mixins: [demoMixin],
}

此时可以使用mixin中的data或methods等

mixin合并规则

  • 如果是data返回值对象,重名了以当前组件为准
  • 生命周期:生命周期的钩子函数会被合并到数组中,都会被调用
  • 如果值为对象,例如methods,components,重名了以当前组件为准

全局混入

在main.js中

app.mixin({
    data() {
        
    },
    methods: {
    
    }
})

setup函数

setup其实就是组件的另一个选项,这个选项强大到可以替代之前编写的大部分其他选项,比如methods,computed,watch等等

setup参数

setup(props,context){

}

props是父组件传递来的值被放在props对象中,因为setup函数不绑定this。 context包含三个属性

  • attrs:所有非props的attribute。例如子组件中绑定的id,class等。
  • slots:父组件传来的插槽
<home>
    <template #default>
    </template>
</home>
  • emit.发送事件。

setup返回值

返回值是一个对象,也就是说可以将setup里的返回值当作vue2的data使用。但是这样是没有响应式的。


<template>
  <div class="hello">
    {{ title }}
  </div>
</template>


  setup() {
    return {
      title: '桂林山水甲天下'
    }
  }

reactiveAPI

写一个简单的计数器

<template>
  <div class="hello">
    <button @click="increment">+1</button>
    {{ counter }}
  </div>
</template>

  setup(props,{attrs}) {
    let counter = 100;
    const increment = () => {
      counter++;
      console.log(counter);
    }
    return {
      counter,
      increment,
    }
  }

此时发现counter不是响应式的 需要引入一个reactive函数,此时代码修改为

<template>
  <div class="hello">
    {{ title }}
    <button @click="increment">+1</button>
    {{ state.counter }}
  </div>
</template>

<script>
import { reactive } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  setup(props,{attrs}) {
    const state = reactive({
      counter: 100
    })
    const increment = () => {
      state.counter++;
    }
    return {
      title: '桂林山水甲天下',
      state,
      increment,
    }
  }
}
</script>

Ref APi

reactiveAPI要求我们传入的是一个对象或者数组类型,如果传入一个基本数据类型会报一个警告, 此时可以使用一个refAPI。ref会返回一个可变的响应式对象,该对象作为一个响应式的引用维护着它内部的值,这就是ref名称的来源。它内部的值是在ref的value属性中被维护的。

<template>
  <div class="hello">
    {{ title }}
    <button @click="increment">+1</button>
    <!-- 当我们在template模板中使用ref对象,它会自动进行解包 -->
    {{ counter }}
  </div>
</template>

<script>
// import { reactive } from 'vue';
import { ref } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  setup(props,{attrs}) {
    let counter = ref(100)
    const increment = () => {
      counter.value++;
    }
    return {
      title: '桂林山水甲天下',
      counter,
      increment,
    }
  }
}

在开发中推荐使用ref,(codewhy讲的) ref解包是一个浅层解包,如果

//此时{{info.counter}}不会正常显示
counter = ref(100)
info = {
counter
}


认识readOnlyAPI

我们可以通过reactive或者ref获取到一个响应式对象,但是在某些情况下,我们传入其他地方的这个响应式对象希望在另一个地方被使用,但不能被修改。此时可以使用readOnly。

<template>
  <div class="hello">
    <button @click="updateState">修改</button>
  </div>
</template>

<script>
import { reactive, ref,readonly } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  setup(props,{attrs}) {
    let counter = ref(100);
    const info = {
      name: 'juju'
    }
    // 1.普通对象
    const readonlyInfo = readonly(info);

    //2.响应式对象
    const info2 = reactive({
      name: 'juju'
    })
    const readonlyinfo2 = readonly(info2)

    //3.ref对象
    const info3 = ref("juju");
    const readonlyinfo3 = readonly(info3);

    const updateState = () => {
      readonlyInfo.name = 'why';   
      readonlyinfo2.name = 'why';
      readonlyinfo3.value = 'why';   //通过返回的readonlyInfo代理修改会报警告
    }

    return {
      updateState
    }
  }
}

此时修改readonly对象会报警告

image.png