vue3中知识点总结(持续更新)

1、具名插槽

Vue3 具名插槽 Named Slots 文档地址

// 具名插槽添加
<slot name="submit"></slot>
 
// 具体地方使用submit插槽时
// v-slot:submit 可以缩写为#submit
<template v-slot:submit>
  <span class="btn btn-danger">Submit</span>
</template>
// 或者
<template #submit>
  <span class="btn btn-danger">Submit</span>
</template>

2、watch监听

应用场景代码:

// watch 简单应用
watch(data, () => {
  document.title = 'updated ' + data.count
})
// watch 的两个参数,代表新的值和旧的值
watch(refData.count, (newValue, oldValue) => {
  console.log('old', oldValue)
  console.log('new', newValue)
  document.title = 'updated ' + data.count
})

// watch 多个值,返回的也是多个值的数组
watch([greetings, data], (newValue, oldValue) => {
  console.log('old', oldValue)
  console.log('new', newValue)
  document.title = 'updated' + greetings.value + data.count
})

// 使用 getter 的写法 watch reactive 对象中的一项
// 注意这里不能直接用data.count;因为data.count不是一个响应式数据,所以用() => data.count 箭头函数的方式
watch([greetings, () => data.count], (newValue, oldValue) => {
  console.log('old', oldValue)
  console.log('new', newValue)
  document.title = 'updated' + greetings.value + data.count
})

示例代码:

<!--
* @Description: Vue3新特性之watch监听 
* @Author: Rulyc
* @Operating:
-->
<template>
  <h1>{{ count }}</h1>
  <h2>{{ double }}</h2>
  <button @click="btnClick">点击+1</button>
</template>

<script lang="ts">
  import { ref, computed, reactive, toRefs, watch } from 'vue' // 引入ref,computed 才能使用
  interface DataProps { // 定义数据类型
    count: number;
    double: number;
    btnClick: () => void;
  }
  export default {
    name: "watch",
    setup() {
     const data: DataProps = reactive({
       count: 0,
       /** 点击事件 */
       btnClick: ()=>{ data.count ++; },
       /** 计算属性 */
       double : computed(()=>{ return data.count * 2 })
     })
      const refData = toRefs(data)
      /** watch监听 */
      // data.double不是响应式数据,故而需要用箭头函数的方式()=> data.double,或者toRefs后的refData.count
      watch([refData.count, ()=> data.double], (newValue, oldValue) => {
        console.log('old', oldValue)
        console.log('new', newValue)
        document.title = 'updated ' + data.count+data.double
      })
      return {
        ...refData
      }
    }
  }
</script>

结果:
在这里插入图片描述

3、ref语法(数据定义)

在这里插入图片描述

代码:

<!--
* @Description: Vue3新特性之Ref 语法
* @Author: Rulyc
* @Operating:
-->
<template>
  <h1>{{ count }}</h1>
  <h2>{{ double }}</h2>
  <button @click="btnClick">点击+1</button>
</template>
<script>
  import { ref, computed } from 'vue' // 引入ref,computed 才能使用
  export default {
    name: "ref_computed",
    setup() {
      // ref是一个函数,他接受一个参数,返回的就是一个神奇的响应式对象
      const count = ref(0)
      /** 计算属性用法 */
      const double = computed(()=>{
        return count.value * 2
      })
      /** 点击事件 */
      const btnClick = ()=> {
        // 更改值用xx.value; 渲染时用xx; 原因vue3底层自动在渲染时处理了
        count.value ++
      }
      return {
        count,
        double,
        btnClick
      }
    }
  }
</script>
<style scoped>
</style>

4、Reactive函数

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

导致这个的原因是:
在这里插入图片描述

如果需要优化,且避免上述问题,我们需要引入toRefs;优化后的完整代码如下:

<!--
* @Description: Vue3新特性之Reactive 语法
* @Author: Rulyc
* @Operating:
-->
<template>
  <h1>{{ count }}</h1>
  <h2>{{ double }}</h2>
  <button @click="btnClick">点击+1</button>
</template>

<script lang="ts">
  import { ref, computed, reactive, toRefs } from 'vue' 
  interface DataProps { // 定义数据类型
    count: number;
    double: number;
    btnClick: () => void;
  }
  export default {
    name: "Reactive_toRefs",
    setup() {
     const data: DataProps = reactive({
       count: 0,
       /** 点击事件 */
       btnClick: ()=>{ data.count ++; },
       /** 计算属性 */
       double : computed(()=>{ return data.count * 2 })
     })
      const refData = toRefs(data)
      return {
        // 此时的数据不是响应式的数据,而是取出的为数据类型,number
       /* count: data.count,
        double: data.double,
        btnClick: data.btnClick*/
        ...refData
      }
    }
  }
</script>
<style scoped>
</style>

使用 ref 还是 reactive 可以选择这样的准则:
第一,就像刚才的原生 javascript 的代码一样,像你平常写普通的 js 代码选择原始类型和对象类型一样来选择是使用 ref 还是 reactive。
第二,所有场景都使用 reactive,但是要记得使用 toRefs 保证 reactive 对象属性保持响应性

5、Vue3中的生命周期函数

在 setup 中使用的 hook 名称和原来生命周期的对应关系
beforeCreate -> 不需要 use setup()
created -> 不需要 use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy-> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
errorCaptured -> onErrorCaptured
// 新增的(调试用的debugger工具函数)
renderTracked -> onRenderTracked
renderTriggered -> onRenderTriggered在这里插入图片描述

<!--
* @Description: 生命周期函数
* @Author: Rulyc
* @Operating:
-->
<template>
  <h1>{{ count }}</h1>
  <h2>{{ double }}</h2>
  <button @click="btnClick">点击+1</button>
</template>

<script lang="ts">
  import { ref, computed, reactive, toRefs, onMounted,  onUpdated, onRenderTriggered } from 'vue' // 引入ref,computed 才能使用
  interface DataProps { // 定义数据类型
    count: number;
    double: number;
    btnClick: () => void;
  }
  export default {
    name: "onMounted",
    setup() {
      /** 挂载 */
      onMounted(() => {
        console.log('mounted')
      })
      /** 数据更新  */
      onUpdated(() => {
        console.log('updated')
      })
      /** 调试 */
      onRenderTriggered((event) => {
        console.log(event)
      })
      const data: DataProps = reactive({
        count: 0,
        /** 点击事件 */
        btnClick: ()=>{ data.count ++; },
        /** 计算属性 */
        double : computed(()=>{ return data.count * 2 })
      })
      const refData = toRefs(data)
      return {
        ...refData
      }
    }
  }
</script>

<style scoped>

</style>

在这里插入图片描述

6、Teleport-瞬间移动组件

Teleport组件的出现时为了解决一个问题: 让元素直接挂在到根元素中(常见的场景就是Dialog弹窗,在界面中使用时包裹在其他组件之中,容易被干扰;样式也在其他组件之中,容易变得非常乱),这时候我们需要把弹窗组件渲染到顶层DOM节点之中,如elementUI中,弹窗、气泡是用的js挂在到body中,虽然解决上述说的问题,但是也存在一些bug,比如气泡的bug; vue3推出了teleport组件解决上述问题。
如下:
在这里插入图片描述
在这里插入图片描述
代码部分:model组件
在与html文件中:
在这里插入图片描述
model组件:

<template>
  <!-- teleport组件有一个to属性,去界面中使用使用id="#modal" -->
  <teleport to="#modal">
    <div id="center" v-if="isOpen">
      <h1>
        this is a modal
        <slot></slot>
      </h1>
      <button @click="btnClick">close</button>
    </div>
  </teleport>
</template>

<script lang="ts">
  import { defineComponent } from 'vue'
  export default defineComponent({
      name: "Teleport",
      props: { // 属性
          isOpen: Boolean
      },
      emits: { // 事件名称
          'close-model': null
      },
      setup(props, context) {
          const btnClick = ()=>{
              context.emit('close-model')
          }
          return {
              btnClick
          }
      },

  })
</script>

<style scoped>
  #center {
    width: 200px;
    height: 200px;
    border: 2px solid black;
    background: white;
    position: fixed;
    left: 50%;
    top: 50%;
    margin-left: -100px;
    margin-top: -100px;
  }
</style>

具体界面使用
button @click=“openBtn”>Open Modal

<TeleportDemo :isOpen=“modelIsOpen” @close-model=“closeBtn”>

import { ref} from ‘vue’;

setup() {
const modelIsOpen = ref(false)
/** 打开弹窗按钮事件 /
const openBtn = ()=>{
modelIsOpen.value = true
}
/
* 关闭弹窗按钮事件 */
const closeBtn = ()=>{
modelIsOpen.value = false
}

return {
    modelIsOpen, // 返回数据
    openBtn, // 返回事件
    closeBtn // 返回事件
}

}

7、Suspense异步组件

Suspense组件是Vue3中的知名功能之一。
它们允许我们的应用程序在等待异步组件时渲染一些后备内容,可以让我们创建一个平滑的用户体验。
值得庆幸的是,Suspense组件非常容易理解,它们甚至不需要任何额外的导入!

可以解决异步请求的困境; Suspense是Vue3推出的一个内置的特殊组件; 如果使用Suspense,需要返回一个Promise

本文主要是展示一哈加载多个异步组件的场景,遇到不稳定问题,及解决方法(加载单个,只需要引入单个组件即可)

创建第一个组件:
AsyncShow

<!--
* @Description: Suspense - 异步请求好帮手
* @Author: Rulyc
* @Operating:
-->
<template>
  <h1>{{ result }}</h1>
</template>

<script lang="ts">
  import { defineComponent } from 'vue'
  export default defineComponent({
      name: "10_AsyncShow",
      setup() {
          /** 需要返回一个Promise, 使用Suspense */
          return new Promise((resolve) => {
              setTimeout(()=>{
                  return resolve({
                      result: 42
                  })
              }, 3000)
          })
      }
  })
</script>

使用 async await , 新建一个 10_AsyncShow_Img组件

<template>
  <img :src="result && result.url" alt="">
</template>

<script lang="ts">
  import { defineComponent } from 'vue'
  import axios from 'axios'
  export default defineComponent({
      name: "10_AsyncShow",
      async setup() {
         const rawData = await axios.get('https://images.dog.ceo/breeds/terrier-irish/n02093991_4404.jpg')
          return {
             result: rawData.config
          }
      }
  })
</script>

使用界面中:(自行引入两个组件,然后使用如下图中)

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

警告中说:是一个实验性的特性,它的API很可能会改变slots,除非只有一个根节点。在

故而这里目前应该暂时展示一个根节点(之前的版本中,是可以展示多个异步组件作为根节点的; 以后版本未确定,还不够稳定)

解决这个问题,初步采用了增加一个div包裹(即增加一个根节点)

<Suspense>
  <template #default>
    <div>
      <AsyncShow></AsyncShow>
      <AsyncShowImg></AsyncShowImg>
    </div>
  </template>
  <template #fallback>
    <div>
      Loading... ---- 异步加载中
    </div>
  </template>
</Suspense>

在4.5.8版本中,是需要增加一个根节点的。目前博主使用的是4.5.8; 之前的版本貌似是不用增加一个根节点。
在这里插入图片描述

补充

单个组件及template上属性说明如下图:
在这里插入图片描述

8、getCurrentInstance获取父元素内容

import { defineComponent, computed, getCurrentInstance } from 'vue'
 setup: function (props, context) {
    const colStyle = computed(() => {
      let {parent} = getCurrentInstance()
      while (parent && parent.type.name !== 'LcRow') {
        parent = parent.parent
      }
      const colGutter : any = parent ? parent.props.gutter : 0
      return {
        paddingLeft: colGutter / 2 + 'px',
        paddingRight: colGutter / 2 + 'px',
      }
    })
    return {
     colStyle
    }
  }

这里我是需要拿到父组件的gutter属性绑定值

9、toRefs、unref

  • toRefs(props) 获取当前绑定的所有属性
  • toRefs(props)[size] // 获取名为size属性的对象
  • unref(toRefs(props)[size] // 获取名为size属性对象的value
import { defineComponent, computed, getCurrentInstance, toRefs, unref } from 'vue'

const classList = []
 /**
   *   toRefs(props) 获取当前绑定的属性
   *   toRefs(props)[size] // 获取名为size属性的对象
   *   unref(toRefs(props)[size] // 获取名为size属性对象的value
   * */
;['xs', 'sm', 'md', 'lg', 'xl'].forEach((size) => {
  if(size == 'xs') { // 为了查看打印效果
    console.log(toRefs(props), 'toRefs(props)')
    console.log(toRefs(props)[size], 'toRefs(props)[size]')
    console.log(unref(toRefs(props)[size]), 'unref(toRefs(props)[size]')
  }
/** 具体判断示例 */
  if (typeof unref(toRefs(props)[size]) === 'number') {
    classList.push(`lc-col-${size}-${unref(toRefs(props)[size])}`)
  } else if (typeof unref(toRefs(props)[size]) === 'object') {
    const propsData = unref(toRefs(props)[size])
    Object.keys(propsData).forEach((prop) => {
      classList.push(
        prop !== 'span'
          ? `lc-col-${size}-${prop}-${propsData[prop]}`
          : `lc-col-${size}-${propsData[prop]}`
      )
    })
  }
})

在这里插入图片描述

10、路由跳转

第一步,引入

import { useRouter } from "vue-router" // 引入路由文件

第二步:setup中

// 路由
 const router = useRouter();

第三步跳转:

router.push('/');

在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值