初探vue3响应性基础 API

2,873 阅读3分钟

由于还不会jsx,先使用vue3+typescript+template模式
网上还有一种tsx+vue模式 以下代码都使用vue3语法(vue3也可以使用vue2语法)

1、项目创建

  • 官网需要vue-cli4+版本才能创建
  • 官网
  • 选择vue3+typescript就可以

2、生命周期

  • 与vue2对比,把beforCreate与created合并成了setUp(在他两之前执行)
vue2-------------vue3
//创建组件前后
beforeCreate  -> setup()
created       -> setup()
//组件挂载到dom前后
beforeMount   -> onBeforeMount
mounted       -> onMounted
//组件更新前后
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
//组件销毁/删除前后
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted  -- 定时器,监听器 事件销毁写在此函数内
  • 上代码
<script lang="ts">
import { //现在使用的方法都要按需引入
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'

export default {
  name: "生命周期",
  setup() {
    console.log('1---setup,组件创建之前')
    onBeforeMount(()=>{
      console.log('2---onBeforeMount,组件挂载到dom前')
    })
    onMounted(()=>{
      console.log('3---onMounted,组件挂载到dom后')
    })
    //组件更新前后--比如数据更新后,会触发组件更新
    onBeforeUpdate(()=>{
      console.log('4---onBeforeUpdate,组件更新前')
    })
    onUpdated(()=>{
      console.log('5---onUpdated,组件更新后')
    })
    //组件销毁前后  节点删除或替换会触发
    onBeforeUnmount(()=>{
      console.log('6---onBeforeUnmount,卸载组件前')
    })
    onUnmounted(()=>{
      console.log('7---onBeforeUnmount,卸载组件后')
    })
  }
}
</script>
  • 结果

3、响应式

3.1 ref

一般使用于基本类型 ,数组也推荐。。修改时需要加上.value

const refCount = ref<number>(0)
refCount.value = 2 //修改时需要加上.value

3.2 reactive

一般使用于对象格式的

  • 我们来实现一个标题点击选中的代码,效果如下

  • 代码

template

<template>
  <div class="life-cycle">
    <span v-for="(i,index) in tabTitle.list"
      :key="i"
      @click="tabTitle.titleClick(index)"
      :class="i===tabTitle.currentTitle?'active':''"
    >
      {{i}}
    </span>
    <div>当前选中的标题:{{tabTitle.currentTitle}}</div>
  </div>
</template>

script

<script lang="ts">
import {
  ref,
  reactive
} from 'vue'
//定义接口
interface TabTitleProps {
  list: string[],
  currentTitle: string,
  titleClick: (index: number) => void
}
export default {
  setup() {
    const tabTitle = reactive<TabTitleProps>({
      list: ['标题A', '标题B', '标题C'],
      currentTitle: '',
      titleClick: (index:number)=>{
        tabTitle.currentTitle = tabTitle.list[index]
      }
    })
    //可以理解为vue2中的data(){return{}}
    return {
      tabTitle
    }
  }
}
</script>

4、template

  • 可以这么玩了
<template>
	<div></div>
	<div></div>
<template>

5、watch

  • 以下代码都在setup方法内执行,要引入watch

5.1 监听单个值(ref)

//watch
    /**
     * refCount:监听的值, refCount 新的值, prevRefCount 旧的值
     */
    const refCount = ref<number>(1)
    watch(refCountTwo, (newVal:number, oldVal:number):void=>{
      console.log('new值', newVal)  // 2
      console.log('old值', oldVal)  // 1
      console.log('-------------')
    })
    setTimeout(()=>{
      refCount.value++
    }, 2000)

5.2 监听多个值 (ref)

    const refCount = ref<number>(1)
    const refCountTwo = ref<number>(100)
//watch 多个
    /**
     * refCount:监听的值, refCount 新的值, prevRefCount 旧的值
     */
    watch([refCount, refCountTwo], (newVal:number, oldVal:number):void=>{
      console.log('new值', newVal)  //[2, 101]
      console.log('old值', oldVal)  //[1, 100]
      console.log('-------------')
    })
    
    setTimeout(()=>{
      refCount.value++
      refCountTwo.value++
    }, 2000)

5.3 深度监听 (reactive)

cosnt person = {
    name: 'lfz',
    age: 11
}
  • 例如要监听person内的age属性
setup(){
    watch(() => personA.age, (newVal: number, oldVal: number): void => {
      console.log('new值', newVal)
      console.log('old值', oldVal)
      console.log('-------------')
    })
    setTimeout(()=>{
      personA.age++
    },1000)
}

5.4 立即执行

watch(\
() => props.name,\
(newValue, oldValue) => {\
console.log(newValue+‘------------’+oldValue);\
},{**immediate : true**}

6、watchEffect

  • 这个直接监听了所有值变化的问题
  • 感觉这个比watch好用
//改变person.age后就执行
watchEffect(()=>{
      console.log(36, personA.age)
})

7、computed

7-1 只读

  • template
<template>
<div>
  <div>a:{{a}}</div>
  <div>b:{{b}}</div>
  <div>a+b={{addVal}}</div>
</div>
</template>
  • script
<script lang="ts">
import {ref, computed} from 'vue'
export default {
  name: "computed",
  setup(){
    const a = ref<number>(1)
    const b = ref<number>(1)
    const addVal:number = computed(():number=> a.value+b.value)
    return {
      addVal,
      a,
      b
    }
  }
}
</script>

7-2 可修改

  • script
const innerVisible = computed({
  get() {
    return props.dialogVisible
  },
  set(value: boolean) {
    emit('update:dialogVisible', value)
  }
})

8.1、全局挂载-方法一

  • 我们在vue2中直接用prototype直接进行挂载。
  • vue3挂载方法 在main.ts
//挂载全局实例
app.config.globalProperties.$test = 'test'  

在组件中使用

import {getCurrentInstance } from 'vue'
setup() {
    // ts proxy 使用
    const { proxy }: any = getCurrentInstance()
    console.log(36, proxy.$test)//test
    return {}
}

9、ref,dom

html

    <span ref="domTest">我是dom</span>

script

improt {ref, onMounted} from 'vue'
export default {
	setup() {
    	const domTest = ref(null) //声明对象
    	onMounted(()=>{
            console.log(43, domTest.value)//输出dom对象
            console.log('3---onMounted,组件挂载到dom后')
    	})
        retrun {
        	domTest//一定要返回
        }
    }
}

10、toRefs

  • 可以用来为源响应式对象上的 property 性创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。(官话)
  • 就是你要解构对象,还要保持响应的功能,这时候就可以用到
  • 下面看demo
import {ref, reactive, toRefs} from 'vue'

setUp() {
/**********************reactive***********************/
    interface Person {
      name: string,
      gender: string
    }

    let person = reactive<Person>({
      name: 'aaa',
      gender: 'male' 
    })
    console.log(33, person) //Proxy{name: 'lufangzhou', gender:'male'}
    //person.name = 'bbb'
    setTimeout(_=>{
      person.name = 'bbb'
    })
    //解构
    //toRefs , 原本是proxy({name: 'lufangzhou', gender:'male'})
    //可以用来为源响应式对象上的 property 性创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。
    const {name, gender} = toRefs(person)
    
    return {
    	name,
        gender
    }
}

11、useRouter

1、 在setup内

import { useRouter } from 'vue-router'
const router = useRouter() // 等于this.$router, $route也是一样

2、不在setup内,若在hooks内

// import { useRoute, useRouter } from "vue-router"
import Vrouter from "@/router"
 
// const router = useRouter();
// const route = useRoute();
 
const route = Vrouter.currentRoute.value
const router = Vrouter
// 监测
watch(() => Vrouter.currentRoute.value.query,
    (query) => {
      ListParams.value = Object.assign(params,query)
      res.value = handleParams()
    })

12、unref

unref():是 val = isRef(val) ? val.value : val 的语法糖。

const valueRef = ref('');
const value = unref(valueRef);
if (!value) {
   console.warning('请输入要拷贝的内容!');
   return;
}

13、内敛语法中获取slot

const slotContent = useSlots().default?.()[0].children