vue3 快速入门系列 —— 其他api-kb88凯时官网登录

来自:
时间:2024-04-23
阅读:
免费资源网,https://freexyz.cn/

他api

前面我们已经学习了 vue3 的一些基础知识,本篇将继续讲解一些常用的其他api,以及较完整的分析vue2 和 vue3 的改变。

浅层响应式数据

shallowref

shallow 中文:“浅层的”

shallowref:浅的 ref()。

先用 ref 写个例子:



这4个按钮都会触发页面数据的变化。

现在将 ref 改成 shallowref,其他都不变。你会发现只有 change1 和 change4 能触发页面数据的变化:



这是因为 change1 中的 a.value 是浅层,而 change2 中的 o.value.name 是深层。

对于大型数据结构,如果只关心整体是否被替换,就可以使用 shallowref,避免使用 ref 将大型数据结构所有层级都转成响应式,这对底层是很大的开销。

shallowreactive

知晓了 shallowref,shallowreactive也类似。

shallowreactive:浅的 reactive()。

请看示例:

现在3个按钮都能修改页面数据:



将 reactive 改为 shallowreactive:

import {shallowreactive} from 'vue'
let o = shallowreactive({
    name: 'p',
    options: {
        age: 18,
    }
})

现在只有 change2 和 change4 能修改页面数据,因为 change3 是多层的,所以失效。

只读数据

readonly

readonly : takes an object (reactive or plain) or a ref and returns a readonly proxy to the original.

readonly 能传入响应式数据,并返回一个只读代理

请看示例:



浏览器呈现:

# 组件a
name: p2
// 按钮1
change name
copyname: p2
// 按钮2
change copyname

点击第一个按钮,发现 copyname 的值也跟着变化了(说明不是一锤子买卖),但是点击第二个按钮,页面数据不会变化。浏览器控制台也会警告:

[vue warn] set operation on key "value" failed: target is readonly. refimpl {__v_isshallow: false, dep: map(1), __v_isref: true, _rawvalue: 'p2', _value: 'p2'}

readonly 只读代理是深的:任何嵌套的属性访问也将是只读的。对比 shallowreadonly 就知道了。

tip:使用场景,比如同事a定义了一个很重要的数据,同事b需要读取该数据,但又担心误操作修改了该数据,就可以通过 readonly 包含数据。

shallowreadonly

readonly 只读代理是深层的,而 shallowreadonly 是浅层的。也就是深层的 shallowreadonly 数据不是只读的。

请看示例:



通过 shallowreadonly 创建一个备份数据,点击第一个按钮没反应,点击第二个按钮,页面变成:

# 组件a
obj: { "name": "p", "options": { "age": 19 } }

shallowreadonly 只处理浅层次的只读。深层次的不管,也就是可以修改。

疑惑:笔者的开发者工具中, copyobj -> options 中的 age 属性没有表示能修改的铅笔图标。应该要有,这样就能保持和代码一致

原始数据

toraw

toraw() can return the original object from proxies created by reactive(), readonly(), shallowreactive() or shallowreadonly().

用于获取一个响应式对象的原始对象。修改原始对象,不会在触发视图。

const foo = {}
const reactivefoo = reactive(foo)
console.log(toraw(reactivefoo) === foo) // true

比如这个使用场景:



markraw

marks an object so that it will never be converted to a proxy. returns the object itself.

标记一个对象,使其永远不会被转换为proxy。返回对象本身。

  • 有些值不应该是响应式的,例如一个复杂的第三方类实例,或者一个vue组件对象。
import {reactive} from 'vue'
let o = {
    getage() {
        console.log(18)
    }
}
// proxy(object) {getage: ƒ}
let o2 = reactive(o)
  • 当使用不可变数据源呈现大型列表时,跳过代理转换可以提高性能。

请问输出什么:

import {reactive} from 'vue'
let o = {
    name: 'p',
    age: 18,
}
let o2 = reactive(o)
console.log(o);
console.log(o2);

答案是:

{name: 'p', age: 18}
proxy(object) {name: 'p', age: 18}

通过 reactive 会将数据转为响应式。

请看 markraw 示例:

import {reactive, markraw} from 'vue'
// 标记 o 不能被转成响应式
let o = markraw({
    getage() {
        console.log(18)
    }
})
let o2 = reactive(o)
// {__v_skip: true, getage: ƒ}
console.log(o2);

比如中国的城市,数据是固定不变的,我不做成响应式的,别人也不许做成响应式的。我可以这么写:

// 中国就这些地方,不会变。我自己不做成响应式的,别人也不许做成响应式的
let citys = markrow([
    {name: '北京'},
    {name: '上海'},
    {name: '深圳'},
    ...
])

customref

自定义 ref 可用于解决内置 ref 不能解决的问题。

ref 用于创建响应式数据,数据一变,视图也会立刻更新。比如要1秒后更新视图,这个 ref 办不到。

先用ref写个例子:input 输入字符,msg 立刻更新:



现在要求:input输入字符后,等待1秒msg才更新。

我们可以用 customref 解决这个问题。

实现如下:



customref() 接收一个工厂函数作为参数,这个工厂函数接受 track 和 trigger 两个函数作为参数,并返回一个带有 get 和 set 方法的对象。

track()trigger() 缺一不可,需配合使用:

  • 缺少 track,即使通知vue 更新了数据,但不会更新视图
  • 缺少 trigger,track 则一直在等着数据变,快变,我要更新视图。但最终没人通知它数据变了

实际工作会将上述功能封装成一个 hooks。使用起来非常方便。就像这样:

// hooks/usemsg.ts
import { customref, } from 'vue'
export function usemsg(value: string, delay = 1000) {
  // customref 传入函数,里面又两个参数
  let msg = customref((track, trigger) => {
    // 防抖
    let timeout: number
    return {
      get() {
        // 告诉 vue 这个数据很重要,要持续关注,数据一旦变化,更新视图
        track()
        return value
      },
      set(newvalue) {
        cleartimeout(timeout)
        timeout = settimeout(() => {
          value = newvalue
          // 告诉vue我更新数据了,你更新视图去吧
          trigger()
        }, delay)
      }
    }
  })
  return msg
}

使用起来和 ref 一样方便。就像这样:



teleport

teleport 中文“传送”

teleport 将其插槽内容渲染到 dom 中的另一个位置。

比如 box 内的内容现在在 box 元素中:



我可以利用 teleport 新增组件将其移到body下面。



现在这段ui内容就移到了 body 下,并且数据链还是之前的,也就是 msg 仍受 button 控制。

tip:to 必填,语法是选择器或实际元素




suspense

d88尊龙官网手机app官网说是一个实验性功能。用来在组件树中协调对异步依赖的处理。

我们首先在子组件中异步请求,请看示例:





tip:我们现在用了 setup 语法糖,没有机会写 async,之所以能这么写,是因为底层帮我们做了。

浏览器查看,发现子组件没有渲染出来。控制台输出:

// main.ts:14 [vue 警告]: 组件 : setup 函数返回了一个 promise,但在父组件树中未找到  边界。带有异步 setup() 的组件必须嵌套在  中才能被渲染。
main.ts:14 [vue warn]: component : setup function returned a promise, but no  boundary was found in the parent component tree. a component with async setup() must be nested in a  in order to be rendered. 
data: {code: 1, data: {…}}

vue 告诉我们需要使用 suspense。

假如我们将 await 用 async 方法包裹,子组件能正常显示。



继续讨论异步的 setup()的kb88凯时官网登录的解决方案。在父组件中使用 suspense 组件即可。请看代码:



子组件也稍微调整下:



利用开发者工具将网速跳到 3g,再次刷新页面,发现先显示loading...,然后在显示

# 组件a
data: { "code": 1, "data": { "name": "阿普的思念", "url": "http://music.163.com/song/media/outer/url?id=2096764279", "picurl": "http://p1.music.126.net/js1io7cwfee6g6ynpyv5fq==/109951169021986117.jpg", "artistsname": "诺米么lodmemo" } }

:数据是一次性出来的,不是先展示 {} 在展示 {...}。所以我们再看d88尊龙官网手机app官网,就能理解下面这段内容:


└─ 
   ├─ 
   │  └─ (组件有异步的 setup())
   └─ 
      ├─  (异步组件)
      └─ (异步组件)

在这个组件树中有多个嵌套组件,要渲染出它们,首先得解析一些异步资源。如果没有 ,则它们每个都需要处理自己的加载、报错和完成状态。在最坏的情况下,我们可能会在页面上看到三个旋转的加载态,在不同的时间显示出内容。

有了 组件后,我们就可以在等待整个多层级组件树中的各个异步依赖获取结果时,在顶层展示出加载中或加载失败的状态。

tip: 在 react 中可以使用 suspense 组件和 react.lazy() 函数来实现组件的延迟加载。就像这样:

import react, {suspense} from 'react'
// 有当 othercomponent 被渲染时,才会动态加载 ‘./math’ 组件
const othercomponent = react.lazy(() => import('./math'))
function testcompoment(){
    return 
loading
}>
}

全局 api 转移到应用对象

在 vue 3 中,一些全局 api 被转移到了应用对象(app)中。

app就是这个:

import { createapp } from 'vue'
const app = createapp({
  /* 根组件选项 */
})

这些 api 以前在 vue 2 中是全局可用的,但在 vue 3 中,出于更好的模块化和灵活性考虑,许多 api 被转移到了应用对象中。

app.component

对应 vue2 中 vue.component,用于注册和获取全局组件。

例如定义一个组件:


在 main.ts 中注册:

import apple from '@/views/apple.vue'
app.component('apple', apple)

现在在任何地方都能直接使用,例如在 childa.vue 中:



app.config

vue2 中有 vue.prototype. 比如 vue.prototype.x = 'hello',在任意模板中 {{x}} 都会输出 hello

这里有 app.config。

比如在 main.ts 中增加:app.config.globalproperties.x = 'hello',在任意组件中就可以获取:


但是 ts 会报错,因为找不到 x。

解决方法在d88尊龙官网手机app官网中有提供。创建一个 ts:

// test.ts
// d88尊龙官网手机app官网:https://cn.vuejs.org/api/application.html#app-config-globalproperties
// 正常工作。
export {}
declare module 'vue' {
  interface componentcustomproperties {
    x: string,
  }
}

然后在 main.ts 中引入:

import '@/utils/test'
app.config.globalproperties.x = 'hello'

不要随便使用,否则你一下定义100个,以后出问题不好维护。

app.directive

vue.directive() - 注册或获取全局指令。

我们用函数形式的指令,就像这样:

// https://v2.cn.vuejs.org/v2/guide/custom-directive.html#函数简写
vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundcolor = binding.value
})

比如我写一个这样的指令:

// main.ts 注册一个全局指令
app.directive('green', (element, {value}, vnode) => {
    element.innertext  = value
    element.style.color = 'green'
})

接着使用指令:



页面呈现:

# 组件a
// 绿色文字
你好兄弟

其他

app.mount - 挂载
app.unmount - 卸载
app.use - 安装插件。例如路由、pinia

非兼容性改变

vue 2 迁移中的一章,列出了 vue 2 对 vue 3 的所有非兼容性改变

tip:强烈建议详细阅读该篇。

全局 api 应用实例

vue 2.x 有许多全局 api 和配置,它们可以全局改变 vue 的行为。例如,要注册全局组件,可以使用 vue.component api

虽然这种声明方式很方便,但它也会导致一些问题。从技术上讲,vue 2 没有“app”的概念,我们定义的应用只是通过 new vue() 创建的根 vue 实例。从同一个 vue 构造函数创建的每个根实例共享相同的全局配置

全局配置使得在同一页面上的多个“应用”在全局配置不同时共享同一个 vue 副本非常困难

为了避免这些问题,在 vue 3 中我们引入了...

一个新的全局 api:createapp

全局和内部 api 都经过了重构,现已支持 treeshaking (摇树优化)

如果你曾经在 vue 中手动操作过 dom,你可能会用过这种方式:

import vue from 'vue'
vue.nexttick(() => {
  // 一些和 dom 有关的东西
})

但是,如果你从来都没有过手动操作 dom 的必要,或者更喜欢使用老式的 window.settimeout() 来代替它,那么 nexttick() 的代码就会变成死代码。

如 webpack 和 rollup (vite 基于它) 这样的模块打包工具支持 tree-shaking,遗憾的是,由于之前的 vue 版本中的代码编写方式,如 vue.nexttick() 这样的全局 api 是不支持 tree-shake 的,不管它们实际上是否被使用了,都会被包含在最终的打包产物中。

tip:vite 基于 rollup

在 vue 3 中,全局和内部 api 都经过了重构,并考虑到了 tree-shaking 的支持。因此,对于 es 模块构建版本来说,全局 api 现在通过具名导出进行访问。例如,我们之前的代码片段现在应该如下所示:

import { nexttick } from 'vue'
nexttick(() => {
  // 一些和 dom 有关的东西
})

通过这一更改,如果模块打包工具支持 tree-shaking,则 vue 应用中未使用的全局 api 将从最终的打包产物中排除,从而获得最佳的文件大小。

v-model 指令在组件上的使用已经被重新设计,替换掉了 v-bind.sync

  • 非兼容:用于自定义组件时,v-model prop 和事件默认名称已更改:
    • prop:value -> modelvalue;
    • 事件:input -> update:modelvalue;
  • 非兼容:v-bind 的 .sync 修饰符和组件的 model 选项已移除,可在 v-model 上加一个参数代替;
  • 新增:现在可以在同一个组件上使用多个 v-model 绑定;
  • 新增:现在可以自定义 v-model 修饰符。

sync 和 model 选项已废除

网站地图