vue3.0 新特性笔记

12 篇文章 4 订阅
6 篇文章 0 订阅

3.0较比于2.x的特性,没用过或者会忘的知识

一、组合式API

这可是VUE3.0的重头戏
在此之前,我们有mixin嘛,就是创建一个对象mixin,然后里面也是有data,created之类的,然后在某个和组件中直接导入就可以使用

组合式API就是更高级的mixin这种
setup组件可以包含mixin,然后mixin也可以包含data\created这些。

1)setup

最早创建的东西,比mounted还要早,里面可以包容万物,data,method,computed都可以,只要在最后面return出去就行

<template>
  <div>
    <div @click="handleClick">
      {{ name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'Index',
  components: {},
  //最早执行
  setup(props, context) {
    return {
      //相当于data中的dell
      name: "dell",
      //方法也是可以的
      handleClick: () => {
        alert(123)
      }
    }
  },
  created() {
    //可以打印,也可以调用setup里面的东西
    console.log(this.$options.setup())
  },
}
</script>

在这里插入图片描述

2)处理响应式数据:ref和reactive

but,单单在setup里面,不是响应式的
处理基础类型 的用ref,处理非基础类型的用reactive

比如现在这个name 2s过后由dell变成aaa,对象也变

<template>
  <div>
    <div>
      <!--      因为在setup里面的,所以写name默认读取的是name.value-->
      {{ name }}
      <br>
      {{ obj }}
    </div>
  </div>
</template>

<script>
import {ref, reactive} from "vue";

export default {
  name: 'Index',
  components: {},
  setup(props, context) {
    //相当于let name = 'dell' 的响应式写法,就只是利用ref
    //其原理就是将 'dell' 变成 proxy({value: 'dell'})的一个响应式引用
    let name = ref('dell');
    //{age:18} 变成 proxy({age:18})的一个响应式引用过
    let obj = reactive({age: 18})
    //异步操作
    setTimeout(() => {
      //基础类型是要 .value,因为在ref已经改变了
      name.value = 'aaa'
      obj.age = 24
    }, 2000)
    return {
      name,
      obj
    }
  },
}
</script>

在这里插入图片描述
在这里插入图片描述

3)更简单地写ref(实验功能)

可以看到,我们想直接改变ref中的数,需要写a.value = xx 这样才能改,但是vue 的实验版本更新了个好用的语法糖

const a = $ref(0)
console.log(a) // 输出0
// console.log(a.value) //会报错

虽然好用,但要开启vue的实验功能
目前还没定稿,实验功能是这样写的,所以真实项目里面就不要用了

二、readonly

正如其名,只读,其写也是一样

  setup(props, context) {

	const {readonly} = Vue
    let obj = reactive({age: 18})
    //此时,这个是不可改的
    let copyObj = readonly(obj)
    //异步操作
    setTimeout(() => {
      //基础类型是要 .value,因为在ref已经改变了
      name.value = 'aaa'
      obj.age = 24
    }, 2000)
    return {
      name,
      obj
    }
  },

三、toRefs

比如之前的,我展示的是{{obj.age}},那我为何不在return的时候直接返回age呢,返回一个字段就好,不用返回某个对象。但是这样就要用toRefs了,不然没有响应式

  setup(props, context) {
    //{age:18} 变成 proxy({age:18})的一个响应式引用过
    let obj = reactive({age: 18})
    //异步操作
    setTimeout(() => {
      obj.age = 24
    }, 2000)

	//加toRefs
    const { age } = toRefs(obj)
    return {
      age
    }
  },

四、toRef

和上面的一样,但是,如果obj里面只有age但没有name,后来想在对象加一个字段,要用这个方法才可以响应式

  setup(props, context) {
    let obj = reactive({age: 18})
    //加了一个从来没有过的字段,要这样做
    let name = toRef(obj,'name')
    //异步操作
    setTimeout(() => {
      obj.age = 24
      //2s后修改
      obj.name = 'qiang'
    }, 2000)

    return {
      obj
    }
  },

五、 context

终于到context的部分了,本节的3个例子都是在子组件里面的

1)attrs

可以打印父中的non-props(就是没有倍props接受的字段)

<template>
  <div>
    <child test="test1"></child>

  </div>
</template>

  setup(props, context) {
    const {attrs} = context
    console.log(attrs.test)
  },

test1

2)slots

可以拿到插槽的东西

<template>
  <div>
    <child>i am parent</child>

  </div>
</template>

  setup(props, context) {
    const {slots} = context
    console.log(slots.default())
  },

打印就是一个虚拟dom

[
    {
        "__v_isVNode": true,
        "__v_skip": true,
        "props": null,
        "key": null,
        "ref": null,
        "scopeId": null,
        "slotScopeIds": null,
        "children": "i am parent",
        "component": null,
        "suspense": null,
        "ssContent": null,
        "ssFallback": null,
        "dirs": null,
        "transition": null,
        "el": null,
        "anchor": null,
        "target": null,
        "targetAnchor": null,
        "staticCount": 0,
        "shapeFlag": 8,
        "patchFlag": 0,
        "dynamicProps": null,
        "dynamicChildren": null,
        "appContext": null
    }
]

3)emit

这个有点绕,我真不知道这玩意存在意义是什么
父写具体的用法,子写emit??

<template>
  <div>
    <child @change="changeMeth">i am parent</child>
  </div>
</template>

<script>
import child from "./components/child.vue";
import {ref, reactive, toRef,readonly} from "vue";

export default {
  name: 'Index',
  components: {
    child
  },

  methods: {
    changeMeth(){
      console.log("SSss")
    }
  },

}
</script>

<template>
  <div>
    <div @click="changeMeth">123</div>
  </div>
</template>

<script>
export default {
  name: 'child',
  setup(props, context) {
    const {emit} = context

    function changeMeth() {
      emit('change')
    }

    return {changeMeth}
  },
}
</script>

六、整理格式和编写

可以看到,setup好像也没有好到哪里去,反而写法更复杂了,所有东西都丢到setup中,就很烦
比如我们可以这样写,具体做什么的可以不用管,懂大概这么个意思就行

<template>
  <div>
    <div>
      <input :value="inputValue" @input="handleInputValueChange" />
      //这里这样,是因为
      <button @click="() => addItemToList(inputValue)">提交</button>
    </div>
    <ul>
      <li v-for="(item, index) in list" :key="index">{{item}}</li>
    </ul>
  </div>
</template>

<script>
import child from "./components/child.vue";
import {ref, reactive, toRef,readonly} from "vue";

// 1、这里做一个方法,这个方法就专门是对list做处理的
const listRelativeEffect = () => {
  const list = reactive([]);
  const addItemToList = (item) => {
    list.push(item);
  }
  return { list, addItemToList }
}

// 2、关于 inputValue 操作的内容进行了封装
const inputRelativeEffect = () => {
  const inputValue = ref('');
  const handleInputValueChange = (e) => {
    inputValue.value = e.target.value
  }
  return { inputValue, handleInputValueChange}
}

export default {
  name: 'Index',
  components: {
    child
  },
  //3、然后我们可以把封装的东西全丢在setup这里,在里面导入然后再return导出,就生成了对应的data和method
  setup() {
    // 流程调度中转
    const { list, addItemToList } = listRelativeEffect();
    const { inputValue, handleInputValueChange} = inputRelativeEffect();
    return {
      list, addItemToList,
      inputValue, handleInputValueChange
    }
  },
  props: {},
  data() {
    return {}
  },
  watch: {},
  computed: {},
  methods: {

  },
  created() {
    console.log(this.$options.setup())
  },
  mounted() {
  },
  activated() {
  },
}
</script>


<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

七、computed

computed还是老样子,不过也可以写在setup里面

<template>
  <div>
    {{ count }}
    <br>
    {{ count5 }}
  </div>
</template>

<script>
import {ref, reactive, toRef, readonly, computed} from "vue";

export default {
  name: 'Index',
  setup() {
    const count = ref(0)

    let count5 = computed({
      get: () => {
        return count.value + 5
      },
      set: (param) => {

      }
    })
    return {count, count5}
  },

}
</script>

0
5

八、watch

watch虽然也和之前一样,但还是有点不一样的

1)ref基础类型

<template>
  <div>
    <input v-model="name"> <br>
    {{ name }}
  </div>
</template>

<script>
import {ref, watch} from "vue";

export default {
  name: 'Index',
  setup() {
  	//基础类型ref
    const name = ref('dell')
    //watch,第一个是监听值,第二个是function,
    watch(name, (currentValue, preValue) => {
      console.log(currentValue, preValue)
    })
    return {name}
  },
}
</script>

//输入l

delll dell

2)监听reactive对象类型中的某个值

基础类型直接用,但是对象类型的话,还没试过,但试过对象类型的某个值

<template>
  <div>
    <input v-model="obj.name"> <br>
    {{ obj.name }}
  </div>
</template>

<script>
import {reactive, ref, watch} from "vue";

export default {
  name: 'Index',
  setup() {
  	//创建对象类型
    const obj = reactive({name: 'dell'})
    //监听对象类型的某个值时,要加箭头函数
    watch(() => obj.name, (currentValue, preValue) => {
      console.log(currentValue, preValue)
    })
    return {obj}

  },
}
</script>

//输入l

delll dell

3)一个watch监听多个值

就尼玛离谱,虽然看起来很离谱,但实际还真有这种写法

<template>
  <div>
    <input v-model="obj.name"> <br>
    {{ obj.name }} <br>
    ------- <br>

    <input v-model="obj.job"> <br>
    {{ obj.job }}
  </div>
</template>

<script>
import {reactive, ref, watch} from "vue";

export default {
  name: 'Index',
  setup() {
    const obj = reactive({name: 'dell', job: 'teacher'})
    //一个watch监听多个值,用数组形势,而后面接受的,也是用数组接受的,
    watch([() => obj.name, () => obj.job], ([curName,curJob],[preName,preJob])=>{
      console.log(curName, curJob)
      console.log('-----------')
      console.log(preName,preJob)
    })
    return {obj}
  },
}
</script>

上面输入l,下面输入s
在这里插入图片描述

delll teacher
dell teacher
隔开
delll teachers
delll teacher

这样就一次性监听多个了

4)watchEffect

这个不需要传任何参数,如果有什么变化的,他就会自动打印的

<template>
  <div>
    <input v-model="obj.name"> <br>
    {{ obj.name }} <br>
    ------- <br>

    <input v-model="obj.job"> <br>
    {{ obj.job }}
  </div>
</template>

<script>
import {reactive, ref, watch, watchEffect} from "vue";

export default {
  name: 'Index',
  setup() {
    const obj = reactive({name: 'dell', job: 'teacher'})
    watchEffect(() => {
      console.log(obj.name)
      console.log(obj.job)
    })
    return {obj}

  },
}
</script>

在这里插入图片描述

5)两者区别

watch和watchEffect,都差不多

  1. watch
    • 具有惰性
    • 参数可以拿到原始数据和当前的值
    • 可以监听多个数据变化
  2. watchEffect
    • 立即执行,没有惰性
    • 不需要传递监听值,全局的
    • 不能获取变化之前的值
    • 不需要传参,写个回调函数就行
    • 多用于异步处理,多用于不需要获取变化前的情况

6)停止监听

都是一样的写法
5秒后,再也不监听

    const stopWatch = watchEffect(() => {
      setTimeout(()=>{
        stopWatch()
      },5000)
    })

九、生命周期在setup中的写法

就比如

  setup() {
    onMounted(() => {
      console.log('sss')
    });
  },

更多生命周期函数参考官网
https://cn.vuejs.org/api/composition-api-lifecycle.html#onmounted

十、setup中的父传子

1)基本使用

说了那么多,父传子的情况肯定会有,但是setup api的还没试过,这就来

<template>
  <div>
    <child/>
  </div>
</template>

<script>
import child from "./components/child.vue";
import {onMounted, provide, reactive, ref, watch, watchEffect} from "vue";

export default {
  name: 'Index',
  components: {
    child
  },
  setup() {
    const name = ref('dell')
    //provide是传给子的工具,key => value
    provide('name',name)
  },
}
</script>

子:

<template>
  <div>
    {{ name }}
  </div>
</template>

<script>
import {inject, reactive} from "vue";

export default {
  name: 'child',
  components: {},
  setup() {
    // inject接受父的setup api传过来的值
    const name = inject('name')
    console.log('父传子', name.value)
    return {name}
  },
}
</script>

在这里插入图片描述

2)改变值,类似于emit

<template>
  <div>
    <child/>
  </div>
</template>

<script>
import child from "./components/child.vue";
import {onMounted, provide, reactive, ref, watch, watchEffect} from "vue";

export default {
  name: 'Index',
  components: {
    child
  },
  setup() {
    const name = ref('dell')
    //provide是传给子的工具,key => value
    provide('name', name)
    //传给子的函数,相当于平时的emit,拿到参数后改变些东西
    provide('click', (value) => {
      name.value = value
    })
  },
}
</script>

<template>
  <div>
    <div @click="click">{{ name }}</div>
  </div>
</template>

<script>
import {inject, reactive} from "vue";

export default {
  name: 'child',
  components: {},
  setup() {
    // inject接受父的setup api传过来的值
    const name = inject('name')
    //父传过来的function,回调给父
    const changeValue = inject('click')
    //点击事件
    const click = () => {
      changeValue('lee')
    }
    return {name, click}
  },
}
</script>

八、复选框

<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />

// 当选中时:
vm.toggle === ‘yes’
// 当未选中时:
vm.toggle === ‘no’

九、父传子还能传函数类型


比如这个,num是一个函数类型的,然后子用Function接受,也是能调用父函数的
感觉这样做,就没有那个$emilt的什么事了

十、父传子的校验

在这里插入图片描述
比如这个,平时可以写类型,默认值,还能写校验值

十一、父传子的一个驼峰命名bug

在这里插入图片描述
父得到名字有-的,但是子只用用驼峰法来写,如果用-写,会识别不出来

十二、单向数据流

一直困扰了我好久的问题,现在终于知道了。
比如子用props接受一个字,虽然可以用 this.xxx接受,只能读不能改,这叫单向数据流。所以解决方法就是在子data里面创建一个变量 b=this.xxx,然后改b就行

十三、没有filter过滤器了

呜呜呜怎么好好的过滤器没有了
尤大推荐用computed来计算。
如果想做成类似全局过滤器那种,可以

// main.js
const app = createApp(App)

app.config.globalProperties.$filters = {
  currencyUSD(value) {
    return '$' + value
  }
}
<template>
  <h1>Bank Account Balance</h1>
  <p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>

十三、函数的特殊写法

function a (param){ }
//等价于
const a = (param) =>{ }

//都是一样的意思,但是用的话都是一样地用a(param)就可以

十四、vue2到vue3的过渡:选项式和组合式的写法

1)简介

vue3.2 以上,默认使用setup包围,这样就不用写return了

<script setup>

</script>

vue2中,我们的写法都是

export default {
  name: 'Index',
  components: {},
  props: {},
  data () {
    return {}
  },
  watch: {},
  computed: {},
  methods: {},
  created () {
  },
  mounted () {
  },
  activated () {
  },
}

但是在vue3中的组合式API,没有这样了,每一个都变了。虽然也可以用vue2的写法,但不推荐,因为时代的潮流不可逆转,程序员注定要学新的东西

2)name

选项式
export default {
  name: 'Index',
}
组合式

3中,名字省略了,你的文件名就是你的name

3)components

选项式
<script>
import Nav from '@/components/Nav'

export default {
  components: { Nav },
}
</script>

<template>
  <div>
    <Nav />
  </div>
</template>
组合式

没有components一个括号,直接导入就可以直接用

<script setup>
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>

      <HelloWorld msg="You did it!" />

</template>

4)props

选项式
export default {
  props: ['a','b'],
}

又或者是

export default {
  props: {
    // 基础类型检查
    //(给出 `null` 和 `undefined` 值则会跳过任何类型检查)
    propA: Number,
    // 多种可能的类型
    propB: [String, Number],
    // 必传,且为 String 类型
    propC: {
      type: String,
      required: true
    },
    // Number 类型的默认值
    propD: {
      type: Number,
      default: 100
    },
    // 对象类型的默认值
    propE: {
      type: Object,
      // 对象或者数组应当用工厂函数返回。
      // 工厂函数会收到组件所接收的原始 props
      // 作为参数
      default(rawProps) {
        return { message: 'hello' }
      }
    },
    // 自定义类型校验函数
    propF: {
      validator(value) {
        // The value must match one of these strings
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 函数类型的默认值
    propG: {
      type: Function,
      // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
      default() {
        return 'Default function'
      }
    }
  }
}

组合式

这样写,用defineProps函数,然后一个常量接受,再使用即可,在html上可以{{foo}}直接使用

<script setup>
const props = defineProps(['foo'])

console.log(props.foo)
</script>

又或者是

const props = defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true
  },
  // Number 类型的默认值
  propD: {
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propE: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  },
  // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})

5)computed

选项式
export default {
  data() {
    return {
      name: 'John Doe',
    }
  },
  computed: {
    // 一个计算属性的 getter
    nameComputed() {
      // `this` 指向当前组件实例
      return name + 'aaaaa'
    }
  }
}
组合式
import { ref, computed } from 'vue'

const name = ref('John Doe')

// 一个计算属性 ref
const nameComputed = computed(() => {
	return name + 'aaaaa'
})

如果想要set和get

import { ref, computed } from 'vue'

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(' ')
  }
})

6)data

选项式
export default {
  data () {
    return {
        a:'123',
        obj:{
            name: 'tom'
        }
    }
  },

}

组合式

没有说直接一个data括号起来,只要在外面定义,用ref或者reactive函数,都默认是当作data响应式的

其中ref用于基础类型,reactive用于非基础类型

const a = ref('123')
const obj = reactive({
  name:'tom'
})

7)watch

选项式
export default {
  data () {
    return {
        someObject:{
            name:'tom'
        }
    }
  },
  watch: {
    // 每当 someObject 改变时,这个函数就会执行
    someObject(newValue, oldValue) {
    	// 变化要做的
    }
  },
}
组合式
import { reactive, watch } from 'vue'

const someObject = reactive({name:'tom'})

// 每当 someObject 改变时,这个函数就会执行
watch(someObject, (newQuestion, oldQuestion) => {
 // 变化要做的
})
番外:watchEffect

watch是每次都只监听一个,watchEffect可以监听所有。每当有数据变化的时候,都会执行该函数

watchEffect(async () => {
    //做异步操作
  const response = await fetch(url.value)
  data.value = await response.json()
})
  • watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。
  • watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。

8)methods

选项式
export default {
  methods: {
      functionName(){
          
      }
  },

}
组合式

组合式就像写普通函数这样用就好了

function functionName(){

}

9)生命周期

生命周期的区别

2和3的周期有点不一样

2:

3:

选项式
export default {
  created () {
  },
  mounted () {
  },
  activated () {
  },
}
//等等诸如此类
组合式
import { onMounted } from 'vue'

onMounted(() => {
	//
})

10)emit

选项式

在子中this.$emit('函数名',参数)

<template>
      <HelloWorld @clickFunction="clickFunction"/>
</template>
export default {
  methods: {
    clickFunction(param){
      console.log('打印参数',param)
    }
  },
}
</script>
export default {
  methods: {
    clickFunction(param){
      console.log('打印参数',param)
    }
  },
  mounted () {
    const param = 123
    this.$emit('clickFunction',param)
  },
}

组合式

<template>
      <HelloWorld @clickFunction="clickFunction"/>
</template>
<script setup>
import HelloWorld from './components/HelloWorld.vue'

const clickFunction = (param) =>{
  console.log('打印参数',param)
}
</script>

import {onMounted} from "vue";

//先调用defineEmits函数,里面是array['函数名']
const emit = defineEmits(['clickFunction'])

//这是一个methods
const clickEmit = () =>{
    //和this.$emit() 的写法一样
  emit('clickFunction','123321')
}

//最后在mounth的时候调用它
onMounted(()=>{
  clickEmit()
})

十五、依赖注入:provide和inject

如果一个页面,是由树型的结构的,就是子组件又有子组件又有子组件,这样如果要一层层地往下传递数据,是非常难的。所以可以在第一级的时候,用provide进行传递,任意的后辈组件都可以用inject 来进行接受

import {provide} from "vue";

//第一季父组件
provide('key',123)

//孙组件
import {inject, onMounted} from "vue";

onMounted(()=>{
  const key = inject('key')
  console.log(key) //打印123
})

十六、组合式函数(重要)

这是一个非常非常非常重要的知识点,涉及到后面很常用的VueUse的使用

  • 尤雨溪说在3中,推荐用组合式函数而不用mixin,因为mixin都是隐形的,mixin多了就会不知道哪个属性是从哪里过来的了

  • 组合式函数和mixin有点相似,也是把同样的东西抽离出去,打包,但是组合式函数更好用

  • 一般文件名或者function,以use开头

1)简单例子

比如这个,组件中使用组合式 API 实现鼠标跟踪功能

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const x = ref(0)
const y = ref(0)

//鼠标移动调用该函数,改变x,y值
function update(event) {
  x.value = event.pageX
  y.value = event.pageY
}

    //原生事件,监听鼠标移动而已,鼠标移动了就调用update函数
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>

//显示xy值
<template>Mouse position is at: {{ x }}, {{ y }}</template>

如果多个组件中用同样的逻辑,这时候就要用到组合式函数打包了

// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'

// 按照惯例,组合式函数名以“use”开头
export function useMouse() {
  // 被组合式函数封装和管理的状态
    //这里用了ref是因为这些数据要被到处去,相当于data
  const x = ref(0)
  const y = ref(0)

  // 组合式函数可以随时更改其状态。
  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }

  // 一个组合式函数也可以挂靠在所属组件的生命周期上
  // 来启动和卸载副作用
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  // 通过返回值暴露所管理的状态
  return { x, y }
    // return {x,y,update:update} //还可以返回一个function,这样给外面就能直接调用
}

然后其他组件直接使用就可以

<script setup>
//直接调用
import { useMouse } from './mouse.js'

//组合式函数return什么,这里就能拿到什么,而且是响应式的    
const { x, y } = useMouse()
//如果想用对象接受也可以
const mouse = reactive(useMouse()) //mouse.x,mouse.y就可以使用
</script>

<template>Mouse position is at: {{ x }}, {{ y }}</template>

而且useMouse是个函数,你也可以传一些参数过去

2)异步状态的例子

如果传参是动态的,会变的,而每次会变的时候我都希望执行该组合式函数,我们可以

  • 判断传参是否为ref或者reactive,是的话利用监听器,不是的话执行一次就可以
  • 如果利用了监听器,则在onUnmounted()的时候要清除监听器
// fetch.js
import { ref, isRef, unref, watchEffect } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)

  function doFetch() {
    // 在请求之前重设状态...
    data.value = null
    error.value = null
    
      //这是一个异步函数
    fetch(xxx)
      
  }

  if (isRef(url)) {
    // 若输入的 URL 是一个 ref,那么启动一个响应式的请求,启动监听器
    watchEffect(doFetch)
  } else {
    // 否则只请求一次
    // 避免监听器的额外开销
    doFetch()
  }

  return { data, error }
}

3)VueUse

建议学习VueUse,因为这个库做的就是组合式函数的应用,都打包好了,下载就行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值