Vue3 新增常用API

vue3 中,vue 暴露了很多新的 api ,我们可以根据自己的需求按需引入,这样打包模块时会减小体积

setup

setup 函数也是 Composition API 的入口函数

<template>
  <div id="test">
    <div>{{ number }}</div>
    <button @click="add">Add</button>
  </div>
</template>

<script>
// 1. 从 vue 中引入 ref 函数
import { ref } from 'vue'

export default {
  name: 'Test',
  setup() {
      // 2. 用 ref 函数包装一个响应式变量 number
      let number = ref(0)
      // 3. 设定一个方法
      // number是被ref函数包装过了的,其值保存在.value中
      cosnt add = () => number.value ++
      // 4. 将 number 和 add 返回出去,供template中使用
      return {
        number,
        add
      }
  }
}
</script>

setup 函数还有两个参数,分别是 propscontext,前者存储着定义当前组件允许外界传递过来的参数名称以及对应的值;后者是一个上下文对象,能从中访问到 attremitslots

其中 emit 就是我们熟悉的 Vue2 中与父组件通信的方法,可以直接拿来调用

生命周期

Vue2Vue3
beforeCreatesetup
createdsetup
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestoryonBeforeUnmount
destoryedonUnmounted

使用,直接在 vue 中导入,再进行直接调用

<template>
  <div id="app"></div>
</template>

<script>
// 从 vue 中引入 多个生命周期函数
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted } from 'vue'
export default {
  name: 'App',
  setup() {
    onBeforeMount(() => {
        // 在挂载前执行某些代码
    })

    onMounted(() => {
        // 在挂载后执行某些代码
    })

    onBeforeUpdate(() => {
        // 在更新前前执行某些代码
    })

    onUpdated(() => {
        // 在更新后执行某些代码
    })

    onBeforeUnmount(() => {
        // 在组件销毁前执行某些代码
    })

    unMounted(() => {
        // 在组件销毁后执行某些代码
    })

    return {

    }
  }
}
</script>

reactive

reactive 方法是用来创建一个响应式数据对象,该 API 也很好的解决了 vue2 通过 defineProperty 实现数据响应的缺陷

<template>
  <div id="app">
   <!-- 4. 访问响应式数据对象中的 count  -->
   {{ state.count }}
  </div>
</template>

<script>
// 1. 从 vue 中导入 reactive 
import { reactive } from 'vue'
export default {
  name: 'App',
  setup() {
    // 2. 创建响应式的数据对象
    const state = reactive({ count: 3 })

    // 3. 将响应式数据对象state return 出去,供template使用
    return {state}
  }
}
</script>

ref

ref 就是通过 reactive 包装了一个对象 ,然后是将值传给该对象中的 value 属性,这也就解释了为什么每次访问时我们都需要加上 .value
我们可以简单地把 ref(obj) 理解为这个样子 reactive({value: obj})

<script>
import { ref, reactive } from 'vue'

export default {
  name: 'App',
  setup() {
    const obj = { count: 3 }
    const state1 = ref(obj)
    const state2 = reactive(obj)

    console.log(state1)
    console.log(state2)
  }
}
</script>

.value 是在 setup 函数中访问 ref 包装后的对象时才需要加的,在 template模板中访问时是不需要的,因为在编译时,会自动识别其是否为 ref 包装过的

建议

  • 基本类型值(StringNmuberBoolean 等)或单值对象(类似像 {count: 3} 这样只有一个属性值的对象)使用 ref
  • 引用类型值(ObjectArray)使用 reactive

toRef

toRef 是将某个对象中的某个值转化为响应式数据,其接收两个参数,第一个参数为 obj 对象;第二个参数为对象中的属性名

<script>
// 1. 导入 toRef
import { toRef } from 'vue'
export default {
  setup() {
    const obj = { count: 3 }
    // 2. 将 obj 对象中属性count的值转化为响应式数据
    const state = toRef(obj, 'count')

    // 3. 将toRef包装过的数据对象返回供template使用
    return {state}
  }
}
</script>

总结

  • ref 是对传入数据的拷贝;toRef 是对传入数据的引用
  • ref 的值改变会更新视图;toRef 的值改变不会更新视图

toRefs

toRef 后,就很好理解 toRefs 了,其作用就是将传入的对象里所有的属性的值都转化为响应式数据对象,该函数支持一个参数,即 obj 对象

<script>
// 1. 导入 toRefs
import { toRefs } from 'vue'
export default {
  setup() {
    const obj = {
      name: 'sanm',
      age: 33
    }
    // 2. 将 obj 对象中属性count的值转化为响应式数据
    const state = toRefs(obj)

    // 3. 打印查看一下
    console.log(state)
  }
}
</script>

toRef

shallowReactive

一个浅层的 reactive,一个用于性能优化的API
reactive 包裹一个对象时,如果对象层级不止一层,那么每层都会用 Proxy 包装
如果用 shallowReactive 包裹,只有在第一层包装 Proxy

shallowRef

一个浅层的 ref,与 shallowReactive 一样是拿来做性能优化的
shallowReactive 是监听对象第一层的数据变化用于驱动视图更新,那么 shallowRef 则是监听 .value 的值的变化来更新视图的

结合 triggerRef 调用后会里面更新视图

toRaw

toRaw 方法是用于获取 refreactive 对象的原始数据的

<script>
import { reactive, toRaw } from 'vue'
export default {
  setup() {
    const obj = {
      name: 'sanm',
      age: 33
    }

    const state = reactive(obj) 
    const raw = toRaw(state)

    console.log(obj === raw)   // true
  }
}
</script>

toRaw 方法入参是 ref 对象时,需要加上 .value 才能获取到原始数据对象

markRaw

markRaw 方法可以将原始数据标记为非响应式,既使用 refreactive 将其包装,仍无法实现数据响应式,其接收一个参数,即原始数据,并返回被标记后的数据

<template>
 <p>{{ state.name }}</p>
 <p>{{ state.age }}</p>
 <button @click="change">改变</button>
</template>

<script>
import { reactive, markRaw } from 'vue'
export default {
  setup() {
    const obj = {
      name: '前端印象',
      age: 33
    }
    // 通过markRaw标记原始数据obj, 使其数据更新不再被追踪
    const raw = markRaw(obj)   
    // 试图用reactive包装raw, 使其变成响应式数据
    const state = reactive(raw) 

    function change() {
      state.age = 27
      console.log(state);
    }

    return { state, change }
  }
}
</script>

改变后,不会更新视图,既没有实现数据响应

provideinject

Vue2 中的 provideinject 作用相同,只不过在 Vue3 中需要手动从 vue 中导入

  • provide :向子组件以及子孙组件传递数据。接收两个参数,第一个参数是 key,即数据的名称;第二个参数为 value,即数据的值
  • inject :接收父组件或祖先组件传递过来的数据。接收一个参数 key,即父组件或祖先组件传递的数据名称
// A.vue
<script>
import { provide } from 'vue'
export default {
  setup() {
    const obj= {
      name: 'sanm',
      age: 33
    }

    // 向子组件以及子孙组件传递名为info的数据
    provide('info', obj)
  }
}
</script>

// B.vue
<script>
import { inject } from 'vue'
export default {
    setup() { 
      // 接收A.vue传递过来的数据
      inject('info')  // {name: 'sanm', age: 33}
    }
}
</script>

// C.vue
<script>
import { inject } from 'vue'
export default {
  setup() { 
    // 接收A.vue传递过来的数据
    inject('info')  // {name: 'sanm', age: 33}
  }
}
</script>

watch && watchEffect

watchwatchEffect 都是用来监视某项数据变化从而执行指定的操作的,但用法上还是有所区别

watchwatch( source, cb, [options] )

参数说明:

  • source:可以是表达式或函数,用于指定监听的依赖对象
  • cb:依赖对象变化后执行的回调函数
  • options:可参数,可以配置的属性有 immediate(立即触发回调函数)、deep(深度监听)

当监听 ref 类型时:

<script>
import { ref, watch } from 'vue'
export default {
  setup() { 
    const state = ref(0)

    watch(state, (nV, oV) => {
      console.log(`原值为${oV}`)
      console.log(`新值为${nV}`)
    })

    setTimeout(() => {
      state.value ++
    }, 1000)
  }
}
</script>

当监听 reactive 类型时:

<script>
import { reactive, watch } from 'vue'
export default {
  setup() { 
    const state = reactive({ count: 0 })

    watch(() => state.count, (nV, oV) => {
      console.log(`原值为${oV}`)
      console.log(`新值为${nV}`)
    })

    setTimeout(() => {
      state.count ++
    }, 1000)
  }
}
</script>

当同时监听多个值时:

<script>
import { reactive, watch } from 'vue'
export default {
  setup() { 
    const state = reactive({ count: 0, name: 'sanm' })

    watch(
      [() => state.count, () => state.name], 
      ([nC, nN], [oC, oN]) => {
        console.log(oC)
        console.log(nC)
        console.log(oN)
        console.log(nN)
      }
    )

    setTimeout(() => {
      state.count ++
      state.name = 'sanmzh'
    }, 1000)
  }
}
</script>

watch 方法的第一个参数我们已经指定了监听的对象,因此当组件初始化时,不会执行第二个参数中的回调函数,若我们想让其初始化时就先执行一遍,可以在第三个参数对象中设置 immediate: true
watch 方法默认是渐层的监听我们指定的数据,例如如果监听的数据有多层嵌套,深层的数据变化不会触发监听的回调,若我们想要其对深层数据也进行监听,可以在第三个参数对象中设置 deep: true

补充
watch 方法会返回一个 stop 方法,若想要停止监听,便可直接执行该 stop 函数


watchEffect,它与 watch 的区别:

  • 不需要手动传入依赖
  • 每次初始化时会执行一次回调函数来自动获取依赖
  • 无法获取到原值,只能得到变化后的值
<script>
import {reactive, watchEffect} from 'vue'
export default {
  setup() { 
    const state = reactive({ count: 0, name: 'sanm' })

    watchEffect(() => {
      console.log(state.count)
      console.log(state.name)
      // 会有一次初始化打印
      // 0
      // sanm
      // 一秒后
      // 1
      // sanmzh
    })

    setTimeout(() => {
      state.count ++
      state.name = 'sanmzh'
    }, 1000)
  }
}
</script>

getCurrentInstance

Vue2 的任何一个组件中想要获取当前组件的实例可以通过 this 来得到,而在 Vue3 中我们大量的代码都在 setup 函数中运行,并且在该函数中 this 指向的是 undefinedVue3 setup 中可以使用 getCurrentInstance 获取 vue 实例

<template>
 <p>{{ num }}</p>
</template>
<script>
import {ref, getCurrentInstance} from 'vue'
export default {
  setup() { 
    const num = ref(3)
    const instance = getCurrentInstance()
    console.log(instance)
    // 主要使用 ctx 和 proxy

    return {num}
  }
}
</script>

useStore && useRouter && useRoute

参考:

useStoreuseRouteruseRoute 都是只能在 setup中才能使用

<script>
import { useStore } from 'vuex'
import { useRouter, userRoute } from 'vue-router'
export default {
  setup() { 
    const store = useStore()
    const route = useRoute()
    const router = useRouter()
    // 和 vue2 使用方法类似

    console.log(store, router, router)
  }
}
</script>

ref

获取到标签元素或组件,在Vue2中,我们获取元素都是通过给元素一个 ref 属性,然后通过 this.$refs.xx 来访问的,但这在Vue3中已经不再适用

<template>
  <div>
    <div ref="el">div元素</div>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue'
export default {
  setup() {
    // 创建一个DOM引用,名称必须与元素的ref属性名相同
    const el = ref(null)

    // 在挂载后才能通过 el 获取到目标元素
    onMounted(() => {
      el.value.innerHTML = 'xxxxxx'
    })

    // 把创建的引用 return 出去
    return {el}
  }
}
</script>

补充
设置的元素引用变量只有在组件挂载后才能访问到,因此在挂载前对元素进行操作都是无效的

如果引用的是一个组件元素,那么获得的将是该组件的实例对象

<think>首先,用户的问题是:“我想查找Vue 3中实现刷新浏览器页面的方法 请问Vue 3实现刷新浏览器页面的方法”。 用户提供了三个引用: - 引用[1]:讨论了Vue中刷新页面的方法,包括location.reload()。 - 引用[2]:提到了location.reload()和this.$router.go(0),以及自动刷新的meta标签。 - 引用[3]:讨论了Vue 3中刷新浏览器页面时请求被取消的问题。 用户指定说这些引用仅供参考,并不是用户真正的需求,我应该尽可能参考用户上一次的问题和我的回答。但在这个对话中,这是第一次交互,所以没有上一次的回答。用户的问题是直接的:Vue 3中实现刷新浏览器页面的方法。 系统指令要求: - 所有行内数学表达式使用$...$格式(但在这个上下文中,可能没有数学内容)。 - 独立公式使用$$...$$格式(同样,可能不适用)。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,如[^1]。 在回答结构上,系统指令说:回答结构清晰,帮助用户逐步解决问题。 用户的问题是关于Vue 3的刷新浏览器页面的方法。所以,我需要基于提供的引用来回答。 关键方法总结: - 方法1:使用location.reload() – 强制刷新整个页面,会导致空白页面。 - 方法2:使用this.$router.go(0) – 在Vue Router中,刷新当前页面,类似location.reload()。 - 方法3:使用meta标签自动刷新 – 例如<meta http-equiv="refresh" content="20">,每隔20秒刷新。 引用[3]提到在Vue 3中刷新页面时请求被取消的问题,这可能与刷新方法的实现有关。 用户特别指定Vue 3,所以我应该专注于Vue 3的上下文。 在Vue 3中,常见的刷新方法是: 1. **location.reload()**:这是纯JavaScript方法,直接在浏览器中刷新页面。缺点是会导致整个页面重新加载,用户体验差。 2. **this.$router.go(0)**:如果使用Vue Router,这个方法可以刷新当前页面。但在Vue Router的文档中,router.go(n)导航历史堆栈,go(0)应该刷新当前页面。 3. **使用Vue Router的导航**:可以通过重新导航到当前路由来模拟刷新,例如使用router.push(currentRoute)或类似。 4. **组件刷新**:而不是整个页面刷新,可以使用Vue的响应性来刷新数据,而不刷新页面,比如重新获取数据。 用户问的是“刷新浏览器页面”,意味着整个页面刷新,所以方法1和2更直接。 引用[2]提到this.$router.go(0)在Vue中可用。 在Vue 3中,由于组合式API,写法可能不同,但核心方法相同。 最佳实践:避免强制刷新整个页面,因为它破坏了SPA(单页应用)的优势,应该使用局部刷新。 但用户明确问刷新浏览器页面的方法,所以我需要提供那些方法。 回答结构: 1. 介绍刷新页面的需求。 2. 列出方法。 3. 描述每个方法的优缺点。 4. 建议最佳实践。 5. 生成相关问题。 引用标识:我需要在使用引用时添加,如[^1]。 例如: - 方法一:location.reload() [^1] - 方法二:this.$router.go(0) [^2] - 方法三:meta自动刷新 [^2] 引用[3]关于请求被取消的问题,我可以提到在刷新时可能遇到这种问题。 结尾生成相关问题。 确保使用中文。 大纲回答: 1. **引言**:解释刷新页面的需求,如在增删改查后刷新数据。 2. **方法列表**: - 使用location.reload():简单但强制刷新整个页面。 - 使用Vue Router的go(0)方法:如果使用router,可以调用this.$router.go(0)。 - 使用meta标签:设置自动刷新。 - 其他方法:如路由重定向或组件重新渲染。 3. **优缺点**:强调强制刷新的缺点(如空白页面、请求取消),建议使用局部数据刷新。 4. **Vue 3特定**:在Vue 3中,如何使用这些方法?例如,在setup函数或script setup中。 5. **示例代码**:提供简单代码片段。 6. **相关问题**:生成3-5个相关问题。 引用标识: - 当提到location.reload时,添加[^1] - 当提到router.go(0)时,添加[^2] - 当提到meta刷新时,添加[^2] - 当提到请求取消问题时,添加[^3] 最终回答。 </think>### Vue 3中实现刷新浏览器页面的方法 在Vue 3项目中,刷新浏览器页面通常用于在数据更新(如增删改查操作)后强制重新加载当前页面,以同步最新状态。虽然Vue提倡单页应用(SPA)的局部更新体验,但有时仍需要整个页面刷新。根据提供的引用内容,我整理了Vue 3常用的刷新方法,并分析了各自的优缺点。核心方法源自JavaScriptVue Router,适用于Vue 3环境。强制刷新可能导致页面短暂空白或请求被取消(如引用[3]所述,当刷新触发时,未完成的Axios请求可能被浏览器标记为“canceled”)[^3],因此建议优先考虑局部数据刷新替代方案。 #### 1. **使用 `location.reload()`(纯JavaScript方法)** - **原理**:调用浏览器的原生方法强制重新加载当前页面,相当于按F5或Ctrl+F5。 - **Vue 3实现**:在组件方法或事件处理器中直接使用。由于Vue 3推荐组合式API(Composition API),可以在`setup()`函数或`<script setup>`中调用。 ```javascript // 示例:在Vue 3组件中实现 import { defineComponent } from &#39;vue&#39;; export default defineComponent({ methods: { refreshPage() { location.reload(); // 刷新整个页面 } } }); // 或使用Composition API <script setup> const refreshPage = () => { location.reload(); // 直接调用 }; </script> ``` - **优缺点**: - 优点:简单易用,无需额外依赖。 - 缺点:强制刷新整个页面,导致页面短暂空白(用户体验差);可能中断未完成请求(如Axios请求被取消)[^3]。 - 适用场景:快速实现刷新,但非推荐方式[^1]。 #### 2. **使用 `this.$router.go(0)`(Vue Router方法)** - **原理**:利用Vue Router的导航方法刷新当前路由。`router.go(0)`会重新加载当前页面,类似`location.reload()`,但更集成于Vue生态系统。 - **Vue 3实现**:需先安装并配置Vue Router。在Vue 3中,通过`useRouter`钩子获取router实例。 ```javascript // 示例:在Vue 3中使用Vue Router import { useRouter } from &#39;vue-router&#39;; export default { setup() { const router = useRouter(); const refreshPage = () => { router.go(0); // 刷新当前页面 }; return { refreshPage }; } }; // 或在模板中直接调用 <button @click="$router.go(0)">刷新页面</button> ``` - **优缺点**: - 优点:与Vue Router集成,适合SPA;代码更简洁。 - 缺点:同样强制刷新,可能导致页面空白和请求取消问题[^2]。 - 适用场景:项目中已使用Vue Router时[^2]。 #### 3. **使用meta标签自动刷新(HTML方法)** - **原理**:在HTML头部添加`<meta>`标签,定时刷新页面。这不是动态方法,适用于特定需求如定时数据更新。 - **Vue 3实现**:在`index.html`或入口文件手动添加标签。Vue 3中无法动态修改,需静态设置。 ```html <!-- 在public/index.html文件中添加 --> <head> <meta http-equiv="refresh" content="30"> <!-- 每隔30秒自动刷新 --> </head> ``` - **优缺点**: - 优点:自动执行,无需用户交互。 - 缺点:无法控制刷新时机;整个页面刷新,用户体验差;不适合动态交互场景[^2]。 - 适用场景:简单定时刷新需求,但少用于Vue 3项目。 #### 最佳实践建议 - **避免强制刷新**:在Vue 3中,优先使用局部数据刷新而非整个页面刷新。例如: - 通过重新调用API获取数据并更新响应式状态(如使用`ref`或`reactive`)。 - 使用Vue Router的路由重定向技巧:先导航到空路由再返回当前路由,模拟刷新但不重新加载整个页面。 ```javascript // 局部刷新示例(推荐) import { useRouter } from &#39;vue-router&#39;; const refreshData = async () => { await router.push(&#39;/empty&#39;); // 临时导航到空路由 router.push(router.currentRoute.value.path); // 返回当前路由,触发组件重新渲染 // 同时调用API重新获取数据 }; ``` - **解决请求取消问题**:刷新页面时,浏览器可能取消未完成的Axios请求(如引用[3]所述)。解决方案: - 在刷新前检查请求状态,使用`AbortController`取消不必要请求。 - 优化数据加载逻辑,避免在刷新时触发多个请求[^3]。 这些方法均可在Vue 3中实现,但强制刷新破坏SPA体验,建议仅在必要时使用。优先考虑响应式数据更新以提升性能[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值