Vue3.0 API的使用

2021-12-21  本文已影响0人  小宁子呀

Vue3.0 整体优势

  1. proxy数据劫持代替object.defineProperty(特点:可以监听数组变化,可以直接修改对象属性等);
  2. Composition API,更好的逻辑复用和代码组织;
  3. 优化VirtualDom,使其编译更快,体积更小;
  4. 更好的TypeScript支持,不再需要借助装饰器;

Vue3.0 注意事项

  1. vue3.0页面中用到的API都需要手动引入
  2. 所有的逻辑代码都要写在setup方法中
  3. template中用到的变量和方法必须return出去才可以访问
  4. 书写TS将script标签属性lang="ts"即可

Vue3.0 生命周期变化

Vue3.0 API的使用

1. 组件的声明

<script lang="ts" >

import {defineComponent} from 'vue'
const Home = defineComponent({
  name: 'Home',
})
export default Home

</script>

2. 组件的引入 和 props类型检测

<script lang="ts" >

import Helloword from '../compontents/helloword'
const Home = defineComponent({
  name: 'Home',
  // 使用子组件
  components: {
    Helloword
  },
  // 检测父组件传入的Props
  props: {
    user: {
      type: String,
      required: true
    }
  }
})
export default Home

</script>

3. defineProps 和 defineEmits

<script lang="ts" setup>

// ......V3+JS
const props = defineProps({
  foo: String
})
const emit = defineEmits(['change', 'delete'])
// ......V3+TS
const props = defineProps<{
  foo: string
  bar?: number
}>()
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
// ......V3+TS接口
interface Props {
  msg?: string
  labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']
})

</script>

4. setup

<script lang="ts" >

const Home = defineComponent({
  name: 'Home',
  setup(props, context) {

  }
})
export default Home

</script>

5. ref

<template>
  <div>{{year}}</div>
</template>

<script lang="ts" >
import {ref} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    let year = ref<string>('2021')
    year.value = '2022'

    return {
      year
    }
  }
})
export default Home
</script>

6. reactive

<script lang="ts" >
interface Student {
  name: string,
  age: string | number,
  class: string
}
interface Todo {
  text: string,
  done: boolean
}
import {reactive} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const state = reactive({ count: 0})
    const year = ref<string>('2021')
    // 当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把响应式数据对象展开为原始的值,不需通过 .value 就可以直接被访问
    const state2 = reactive(year)
    // TS给定变量类型的几种方式
    const studentA = reactive<Student>({ name: 'studentA', age: 11, class: 'studentA'})
    const studentB: Student = reactive({ name: 'studentB', age: 22, class: 'studentB'})
    const studentC = reactive({ name: 'studentC', age: 33, class: 'studentC'}) as Student
    const todoList = reactive<Array<Todo>>([
      { text: '待办01', done: true},
      { text: '待办02', done: false}
    ])

    return {
      state2,
      todoList
    }
  }
})
export default Home
</script>

7. shallowReactive

<script lang="ts" >
import {shallowReactive} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const deepobj = {
      a: 1,
      first: {
        b: 2,
        second: {
          c: 3
        }
      }
    }
    const newdeepobj = shallowReactive(deepobj)
    newdeepobj.a = 11 // 第一层改变,更新视图
    newdeepobj.first.b = 22 // 其它层级,不会更新视图

    return {
      newdeepobj
    }
  }
})
export default Home
</script>

8. isRef

<script lang="ts" >
import {ref, isRef} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const year = ref('2021')
    const getVal = isRef(year) ? year.value : '默认年份'

    return {
      getVal
    }
  }
})
export default Home
</script>

9. toRef

<script lang="ts" >
import {toRef} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const data = {count: 3}
    const newdata = toRef(data, 'count')

    return {
      getVal
    }
  }
})
export default Home
</script>

10. toRefs

<script lang="ts" >
import {reactive, toRefs} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const state = reactive({ name: 'zs', age: 22, gender: 0 })
    const newstate = toRefs(state) // 转为普通数据
    const obj = { name: 'ls', age: 20, gender: 1 }
    const newobj = toRefs(obj) // 转为响应式数据

    return {}
  }
})
export default Home
</script>

11. shallowRef

<script lang="ts" >
import {shallowRef, triggerRef} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const multistoreyobj ={
      a: 1,
      first: {
        b: 2,
        second: {
          c: 3
        }
      }
    }
    const newmultistoreyobj= shallowRef(multistoreyobj)
    newmultistoreyobj.value.first.b = 8// 场景一: 改变数据,但不会更新视图
    newmultistoreyobj.value.first.second.c = 9// 改变数据,但不会更新视图
    newmultistoreyobj.value = {// 场景二: 将整个.value 重新赋值了,视图就立马更新了
      a: 11,
      first: {
        b: 22,
        second: {
          c: 33
        }
      }
    }

    return {}
  }
})
export default Home
</script>

12. triggerRef

// 接着上个示例代码看
newmultistoreyobj.value.first.b = 8// 改变数据不触发更新
triggerRef(newmultistoreyobj)// 场景三:  调用triggerRef方法驱动更新

13. toRaw

<script lang="ts" >
import {reactive, toRaw} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const olddatas = {
      name: 'olddatas',
      age: 11
    }
    const newdatas = reactive(olddatas) // 包装旧数据
    const raw = toRaw(newdatas)// 拿到数据源 (注意:如果操作的是ref对象,参数需要写成newdatas.value)
    raw.age = 111// 由于是引用数据源,所以修改数据源后引用的一方也会改变,但不触发更新 (所以:可用作性能优化)

    return {}
  }
})
export default Home
</script>

14. markRaw

<script lang="ts" >
import {reactive, markRaw} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const objA = { a: 1}
    const rawA = markRaw(objA)// 通过markRaw标记原始数据objA, 使其数据更新不再被追踪
    const stateA = reactive(raw)// 试图用reactive包装raw, 使其变成响应式数据
    stateA.age = 90//响应无效:修改数据,不触发更新

    return {}
  }
})
export default Home
</script>

15. computed

<script lang="ts" >
import {ref, computed} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const refCount = ref(1)
    let computedCount = computed(() => refCount.value + 1)
    console.log(computedCount) // 读取

    return {}
  }
})
export default Home
</script>
<script lang="ts" >
import {ref, computed} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const refCount = ref(1)
    let computedCount2 = computed({
      get: () => refCount.value + 1,
      set: val => refCount.value = val - 5
    })
    console.log(computedCount2.value) // 读取
    computedCount2.value = 10 // 写入
    console.log(computedCount2.value)
    console.log(refCount.value)

    return {}
  }
})
export default Home
</script>

16. watch

<script lang="ts" >
import {ref, watch} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    let refCount = ref<string>('20')
    let year = ref<string>('2021')
    let month = ref<string>('11')
    watch(refCount, () => {console.log('监听refCount',refCount.value)})
    watch(
      [year, month],
      ([newYear, newMonth], [oldYear, oldMonth]) => {
        console.log('监听year',newYear,oldYear)
        console.log('监听month',newMonth,oldMonth)
      }
    )
    return {}
  }
})
export default Home
</script>
<script lang="ts" >
import {watch} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    let refCount = ref<string>('20')
    const stop = watch(refCount, () => {})
    stop()
    return {}
  }
})
export default Home
</script>
<script lang="ts" >
import {watch} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    let refCount = ref<string>('20')
    const asyncPrint = (val: any) => {// 异步任务
      return setTimeout(() => {
        console.log(val)
      },1000)
    }
    watch(
      refCount,
      (newValue, oldValue, onCleanup) => {
        const timerId = asyncPrint(refCount)// 执行异步任务,并得到关联的timerId
        onCleanup(() => clearTimeout(timerId))// 如果watch监听被重复执行,则会清除上次未完成的任务
      }
    )

    return {}
  }
})
export default Home
</script>

17. watchEffect

<script lang="ts" >
import {watchEffect} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const stateB = reactive({ count: 0, name: 'zs' })
    setTimeout(() => {
      stateB.count ++
      stateB.name = 'ls'
    }, 1000)
    watchEffect(() => {
      console.log(stateB.count) // 初始化时打印:0,zs
      console.log(stateB.name) // 1秒后打印:1,1s
    })

    return {}
  }
})
export default Home
</script>

18. getCurrentInstance

<script lang="ts" >
import {getCurrentInstance} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    // instance.ctx接近this的概念   instance.proxy是包装过的响应式this
    const instance = getCurrentInstance()
    console.log(instance)
    return {}
  }
})
export default Home
</script>

19. useStore

<script lang="ts" >
import {store} from 'vuex'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const store = useStore()// 获取 vuex 实例
    console.log(store)
    return {}
  }
})
export default Home
</script>

20. useRoute & useRouter

<script lang="ts" >
import {useRoute, useRouter} from 'vuex'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const route = useRoute() // 相当于 vue2 中的 this.$route
    const router = useRouter() // 相当于 vue2 中的 this.$router
    console.log(route,router)
    return {}
  }
})
export default Home
</script>

21. provide & inject

import {provide} from 'vue'
// 父组件向下传递
const color = ref('orange')
provide('themecolor',color)
// 子组件接收变量
const resultcolor = inject('themecolor')

22. 节点的引用 -- dom的引用

<template>
  <h3 ref="h3Ref">h3的DOM引用</h3>
  <button @click="clickBtn">弹窗</button>
</template>

<script lang="ts" >
import {ref, Ref} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const method = {
      clickBtn: () => {
        let color = h3Ref.value.style.color
        alert(color)
      }
    }
    const h3Ref:Ref = ref(null) // 创建一个响应式dom的引用,传入null
    onMounted(() => {// DOM首次加载完毕,才能取到元素
      h3Ref.value.style.color = 'red' // 为DOM元素设置样式颜色 , h3Ref.value是原生DOM对象
      // (h3Ref as Ref).value.style.color = 'red'// 初始变量不给定Ref类型的话 可以使用断言语法规避报错
    })

    return {
      ...method, // 一次性展开所有方法
      h3Ref, // 把DOM的引用抛出使用
    }
  }
})
export default Home
</script>

23. 节点的引用 -- 组件的引用

<template>
  <!-- 子组件 -->
  <HelloWorld ref="comRef" msg="Welcome to Your Vue.js + TypeScript App"/>
</template>

<script lang="ts" >
import {ref, Ref} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    const comRef: any = ref(null)
    console.log(comRef.value.str1) // 打印子组件的变量str1值
    comRef.valye.setStr1() // 调用子组件的方法设置str1值
    console.log(comRef.value.str1) // 打印发现子组件的str1被改变了

    return {
      comRef // 把组件的引用抛出使用
    }
  }
})
export default Home
</script>

24. nextTick

Vue3.0 CSS的使用

1. 状态驱动的动态 CSS

<template>
  <button class="dynamic">状态驱动的动态 CSS</button>
</template>

<script lang="ts" >
import {ref} from 'vue'
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {
    let btnBg = ref<string>('blue')
    setTimeout(()=>{btnBg.value='orange'}, 2000)

    return {
      btnBg,
    }
  }
})
export default Home
</script>

<style lang="less" scoped> // scoped隔离样式作用域,不需要任何的 polyfill,通过PostCss转换内容实现
.dynamic{
  /* 绑定变量 */
  background: v-bind(btnBg)
}
</style>

2. 深度选择器

<template>
  <div class="home">
  </div>
</template>

<script lang="ts" >
const Home = defineComponent({
  name: 'Home',
  setup(props, context) {

    return {}
  }
})
export default Home
</script>

<style lang="less" scoped>
.home :deep(.btn_a) {
  background: red
}
</style>

3. 插槽选择器

<style lang="less" scoped>
:slotted(div) {
  background: #000
}
</style>

4. 全局选择器

<style lang="less" scoped>
:global(.background_red) {
  background: red
}
</style>

5. 混合使用局部与全局样式

6. <style module>

<style module>
.btn_b {
  background: brown
}
</style>

7. 自定义注入名称

<style module="moduleC">
.btn_c {
  background: skyblue
}
</style>

8. 与组合式 API 一同使用

<style module="moduleD">
/* 默认, 返回 <style module> 中的类
useCssModule()
命名, 返回 <style module="classes"> 中的类
useCssModule('classes') */
.btn_d {
  background: greenyellow
}
</style>
上一篇 下一篇

猜你喜欢

热点阅读