vue - 基本使用

转载改编自:https://www.bilibili.com/video/BV1Ap4y1W7MG/


文章目录

    • 二、Composition API(组合式API)
      • 1、setup
      • 2、API - ref
      • 3、API - reactive (对象)
      • 4、API - toRefs
    • 三、Provide与Inject(提供/注入)
      • 1、Vue2写法
      • 2、Vue3写法
      • 3、响应性
    • 四、Teleport(传送门)
    • 五、Suspense(等待)
    • 六、Fragment(碎片)
    • 七、TreeShaking(消除未使用代码)
    • 八、Performance(性能)
      • 1、diff方法优化
      • 2、静态提升
      • 3、cacheHandlers 事件侦听器缓存
      • 4、ssr渲染
    • 九、Setup的生命周期
    • 十、TypeScript支持


二、Composition API(组合式API)

相当于 React Hooks

我们先使用以前vue2的方式实现一个累加:

<template>
  <h2>{{count}}</h2>
  <button @click="btnClick">累加</button>
</template>

<script>
export default {
    data(){
        return {
            count: 0
        }
    },
    methods: {
        btnClick(){
            this.count++;
        }
    }
}
</script>

这套代码可以实现一个累加的效果,但如果以后我们想把这个组件中的 count 字段与 btnClick 单独拎出来管理,那就比较麻烦了,因为 countbtnClick 不在同一个方法内,很难抽离。



1、setup

setup有以下特性:

  1. setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数 也就说在 setup函数中是无法 使用 data 和 methods 中的数据和方法的
  2. setup函数是 Composition API(组合API)的入口
  3. 在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用
  4. 由于我们不能在 setup函数中使用 data 和 methods,所以Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined
  5. setup函数只能是同步的不能是异步的

2、API - ref

我们先来体验一下vue3怎么处理这个累加效果:

<template>
  <h2>{{count}}</h2>
  <button @click="btnClick">累加</button>
</template>

<script>
import {ref} from 'vue'
export default {
    data(){
        return {
            count: 0
        }
    },
    setup(){
        const count = ref(1);	// 此时我们使用ref指定count的默认值为1,因此上面data中的count会失效
        let btnClick = () => {
            count.value++;		// 修改ref中的值要用xxx.value
        }
        return {count, btnClick}
    }
}

此时如果我想单独管理这个累加效果,我就可以这么操作:

<template>
  <h2>{{count}}</h2>
  <button @click="btnClick">累加</button>
</template>

<script>
import {ref} from 'vue'
export default {
    data(){
        return {
            // count: 0		// 一旦把setup中的代码抽离,return中对应的值要去掉,否则ref无效
        }
    },
    setup(){
      	// 函数调用后就会返回一个对象,因此我们直接return
        return clickCountFn()
      	// 如果后期还想同时返回其他数据,可以将clickCountFn()的返回结果展开
      	// return {...clickCountFn(), 其他数据}
    }
}

// 封装一个函数,这样这块功能我们就能单独管理了
function clickCountFn(){
    const count = ref(1);
    let btnClick = () => {
        count.value++;
    }
    return {count, btnClick}
}
</script>

3、API - reactive (对象)

再来了解另一个API :

reactive函数和ref作用非常接近,但是它的参数是一个对象,我们可以在对象中定义其方法,而通过这个形式,就不需要再对其进行进行 .value 调用了。

  • reactive 往往会搭配 toRefs 一起使用
  • 使用 reactive 生成的对象与 ref 生成的值都是响应式的。
<template>
  <h2>{{count}}</h2>
  <button @click="btnClick">累加</button>
  
  <p>姓名:{{obj.username}}</p>
  <button @click="btnClick1">修改姓名</button>
</template>

<script>
import {ref, reactive} from 'vue'
export default {
    setup(){
      	// 使用reactive
        let obj = reactive({
            username: "Jack"
        })
        let btnClick1 = () => {
            obj.username = "Mary"
        }
				return {...clickCountFn(), obj, btnClick1}
    }
}

function clickCountFn(){
    const count = ref(1);
    let btnClick = () => {
        count.value++;
    }
    return {count, btnClick}
}
</script>

这里可以看到我们在 html 中调用数据时,使用的是 obj.username ,那我们是否可以直接写 username 呢?答案是可以的,但这里需要注意:

由于reactive返回的对象本质上已经是一个Proxy对象,所以通过…扩展符号展开的属性,是无法进行响应式的

也就是说,如果这么写:

return {...clickCountFn(), ...obj, btnClick1}

那么是无法实现的。


4、API - toRefs

正确的写法应该是:

<template>
  <h2>{{count}}</h2>
  <button @click="btnClick">累加</button>
  
	<!-- 无需obj.username,直接username即可 -->
  <p>姓名:{{username}}</p>
  <button @click="btnClick1">修改姓名</button>
</ template>

<script>
// 新增toRefs方法
import {ref, reactive, toRefs} from 'vue'
export default {
    setup(){
        let obj = reactive({
            username: "Jack"
        })
        let btnClick1 = () => {
            obj.username = "Mary"
        }
        // 通过toRefs方法
        let refObj = toRefs(obj);
      	// 通过...refObj将数据扩展
        return {...clickCountFn(), ...refObj, btnClick1}
    }
}

// 其他代码...
</script>

三、Provide与Inject(提供/注入)


1、Vue2写法

以往我们的父传子是通过props传的:

<!-- Father.vue父组件 -->
<template>
  <Child :num="num" />
</template>

<script>
import Child from './Child.vue'
export default {
    data(){
        return {
            num: 123
        }
    },
    components: {
        Child
    }
}
</script>

<!-- Child.vue子组件 -->
<template>
  <h2>父组件传过来的值:{{num}}</h2>
</template>

<script>
export default {
    props: ['num']
}
</script>

这个时候限制死了数据必须来自父组件,我们其实还有 ProvideInject

<!-- Father.vue父组件 -->
<template>
  <Child />
</template>

<script>
import Child from './Child.vue'
export default {
    components: {
        Child
    },
    provide: {
        num: 456
    }
}
</script>

<!-- Child.vue子组件 -->
<template>
  <h2>父组件传过来的值:{{num}}</h2>
</template>

<script>
export default {
    inject: ['num']
}
</script>

Provide/Inject 相比于 props 的好处在于:

如果组件嵌套较多,那么 props 需要一级一级往下传递,后期很难维护。Provide+Inject 相当于是跨级组件传值,比如孙子组件也想用上面这个 num 的值,就不用一级一级往下传,直接在孙子组件使用即可:

<!-- Sun.vue孙子组件 -->
<template>
  <h4>孙子组件:{{num}}</h4>
</template>

<script>
export default {
	  // 将Sun组件在Child组件中引入,即可实现跨级组件传值
    inject: ['num']
}
</script>

2、Vue3写法

vue3中的 provide/inject。两者都只能在当前活动实例的 setup() 期间调用。

格式为:

// provide
import {provide} from 'vue' // 显式导入
export default {
  setup() {
    // 此处name必须是String类型,value则不限制
    provide(name, value)
  }
}

// inject
import {inject} from 'vue' // 显式导入
export default {
    setup(){
      	// name即为传过来的字段,第二个参数可选,可填写默认值
        const val = inject(name, defaultValue);
      	return {val}
    }
}

我们修改以上案例的代码:

<!-- Father.vue父组件 -->
<template>
  <Child />
</template>

<script>
import {provide} from 'vue' // 显式导入
import Child from './Child.vue'
export default {
    components: {
        Child
    },
    setup(){
        provide('num', 789)
    }
}
</script>

<!-- Sun.vue孙子组件 -->
<template>
  <h4>孙子组件:{{mynum}}</h4>
</template>

<script>
import {inject} from 'vue' // 显式导入
export default {
    setup(){
        const mynum = inject('num');
        return {mynum}
    }
}
</script>

3、响应性

所谓的 Provide/Inject 响应性,其实就是把传递的值结合上文提及的 refreactive 一起使用:

<!-- Father.vue父组件 -->
<template>
  <Child />
  <button @click="changeNumFn">修改num</button>
</template>

<script>
import {provide, ref} from 'vue' // 显式导入
import Child from './Child.vue'
export default {
    components: {
        Child
    },
    setup(){
      	// 使用ref来定义num的值
        const num = ref(123);

      	// 声明一个函数,专门用于修改num
        let changeNumFn = () => {
            num.value = 456;
        }

        provide('num', num)

      	// 返回这个函数
        return {changeNumFn}
    }
}
</script>

此时,当你点击按钮时,孙子组件接收到的 num 就会被修改了。


四、Teleport(传送门)

在vue2中,想要将子节点渲染到存在于父组件以外的 DOM 节点时,需要通过第三方库 portal-vue 去实现。而vue3中,Teleport 是一种能够将我们的模板移动到 DOMVue app 之外的其他位置的技术。

官方文档:《teleport》

举个最简单的例子:

我们在 index.html#app 同级的地方新增一个 #test 元素:

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

由于vue的 main.js 中规定了打包出来的代码都放入 #app 中:

createApp(App).mount('#app')

因此,你现在没有办法将代码放入 #test 中。此时,我们可以使用传送门:

App.vue 中:

<template>
  <Home />
</template>

<script>
import Home from './components/Home.vue'
export default {
  name: 'App',
  components: {
    Home
  }
}
</script>

Home.vue 中:

<template>
  <p>这段话是渲染在#app中的</p>
  <teleport to="#test">
      <p>这段话是渲染在#test中的--1</p>
  </teleport>
	<teleport to="#test">
      <p>这段话是渲染在#test中的--2</p>
  </teleport>
</template>

此时,你打开浏览器控制台,就可以看到第2、3个p标签已经被渲染到 #test 中。

备注:

1、标签身上都to属性,填写的是css选择器。

2、多个传送门书写时,会按照自上而下的顺序传送至另一个DOM元素。


五、Suspense(等待)

Suspense组件用于在等待某个异步组件解析时显示后备内容。

那我们什么时候需要使用异步组件呢?多了去了,比如:

  • 在页面加载之前显示加载动画
  • 显示占位符内容
  • 处理延迟加载的图像

那么,让我们看看 Suspense 怎么使用,我们先来提一个需求:

在等待组件获取数据并解析时显示“玩命加载中…”之类的内容

OK,我们来写一个 Article.vue 组件:

<template>
  <p>{{ content }}</p>
</template>

<script>
import { ref } from "vue";
export default{
  async setup() {
    let content = ref('内容')
    content.value = await new Promise((resolve,reject)=>{
        setTimeout(() => {
            // 3秒后修改content
            resolve("你好世界");
        }, 3000);
    })
    return {content}
  },
}
</script>

用个 Home.vue 组件来调用它:

<template
  <Suspense>
      <template #default>
          <Article></Article>
      </template>
      <template #fallback>
          <p>玩命加载中...</p>
      </template>
  </Suspense>
</template>

<script>
import Article from './Article.vue'
export default {
    components:{
        Article
    }
}
</script>

可以看出,<Suspense> 中,包含了两个template标签,#default 定义了我们要写入的内容, #fallback 定义了我们要预显示的内容。

⚠️ 注意:

作为template中的内容(即插槽),必须要有根元素。


六、Fragment(碎片)

vue2中,如果你创建一个Vue组件,那么它只能有一个根节点。这意味着不能创建这样的组件:

<template>
	<div>你好</div>
	<div>世界</div>
</template>

原因是代表任何Vue组件的Vue实例需要绑定到一个单一的DOM元素中。唯一可以创建一个具有多个DOM节点的组件的方法就是创建一个没有底层Vue实例的功能组件。

这情况同样存在于react,但react可以使用空标签 <></> 来包裹,或者是使用一个名为Fragment的虚拟元素:

class Columns extends React.Component {
  render() {
    return (
    	<React.Fragment>
      	<td>你好</td>
        <td>世界</td>
      </React.Fragment>
    )
  }
}

尽管Fragment看起来像一个普通的DOM元素,但它是虚拟的,根本不会在DOM树中呈现。目前你可以在Vue 2中使用vue-fragments库来使用Fragments,而在Vue 3中,你直接使用就行了,无需引入任何库。


七、TreeShaking(消除未使用代码)

TreeShaking 是一个术语,指的是在打包构建过程中移除没有被引用到的代码,这些代码可以成为 dead code。这个概念最早在基于 ES6 的打包工具 Rollup 中提出,后来被引入到 webpack 中。TreeShaking 比较依赖于 ES6 模块系统的静态结构特性,比如 importexport

文档参考:https://vue3js.cn/docs/zh/guide/migration/global-api-treeshaking.html#_2-x-%E8%AF%AD%E6%B3%95

举个例子:

vue2中我们常使用 Vue.nextTick(()=>{}) 来预操作DOM,但有时候我们不用这个 nextTick ,比如改用别的方式来代替(如setTimeout),那么项目打包时,vue 全局的 nextTick 就成为一个多余的代码,从而使你的项目打包体积变大。

在vue3中,官方团队重构了所有全局 API 的组织方式,让所有的 API 都支持了 TreeShaking。所以vue3中如果还想使用全局的 nextTick ,就需要引入:

import { nextTick } from 'vue';
 
nextTick(() => {
  // 和 DOM 有关的一些操作
});

如果你在 Vue 3 中不引入而直接调用 Vue.nextTick() ,就会得到一个报错:undefined is not a function

官方也给出了Vue 2.x 中的受此更改影响的全局 API:

  • Vue.nextTick
  • Vue.observable (用 Vue.reactive 替换)
  • Vue.version
  • Vue.compile (仅全构建)
  • Vue.set (仅兼容构建)
  • Vue.delete (仅兼容构建)

八、Performance(性能)

vue3.0相对于vue2.0来说性能快1.2到1.5倍,主要原因如下:


1、diff方法优化

  • Vue2 中的虚拟dom是进行全量的对比
  • Vue3 新增了静态标记(PatchFlag),只比对带有 PF 的节点,并且通过 Flag 的信息得知 当前节点要比对的具体内容。

2、静态提升

  • Vue2中无论元素是否参与更新, 每次都会重新创建, 然后再渲染
  • Vue3中对于不参与更新的元素, 会做静态提升, 只会被创建一次, 在渲染时直接复用即可

3、cacheHandlers 事件侦听器缓存

  • 默认情况下onClick会被视为动态绑定, 所以每次都会去追踪它的变化
  • 但是因为是同一个函数,所以没有追踪变化, 直接缓存起来复用即可

4、ssr渲染

  • 当有大量静态的内容时候,这些内容会被当做纯字符串推进一个buffer里面, 即使存在动态的绑定,会通过模板插值嵌入进去。这样会比通过虚拟dmo来渲染的快上很多很多。
  • 当静态内容大到一定量级时候,会用_createStaticVNode方法在客户端去生成一个static node, 这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。

九、Setup的生命周期

组合式API需要在setup中使用,setup中含有的生命钩子与vue的大体一致:

具体参考:《setup生命周期钩子》


十、TypeScript支持

vue3新增了对TS语法的支持。


2024-01-16

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/593394.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3(实现上下无限来往滚动)

一、问题描述 一般在大屏项目中&#xff0c;很常见的效果&#xff0c;就是容器中的内容缓慢地向下移动&#xff0c;直到底部停止&#xff0c;然后快速滚动回顶部&#xff0c;然后接着缓慢滚动到底部。并且在特定的情况下&#xff0c;还需要进行一些小交互&#xff0c;那就还得让…

RabbitMQ之生产批量发送

为什么要用生产批量发送&#xff1f; 批量发送消息&#xff0c;可以提高MQ发送性能。但是 RabbitMQ 并没有提供了批量发送消息的 API 接口,使用 spring-amqp 的 BatchingRabbitTemplate 实现批量能力。 SimpleBatchingStrategy 发送策略满足以下规则会进行发送&#xff1a; ba…

FreeRTOS低功耗模式(1-19)

低功耗模式简介(了解) 很多应用场合对于功耗的要求很严格&#xff0c;比如可穿戴低功耗产品、物联网低功耗产品等 一般MCU都有相应的低功耗模式,裸机开发时可以使用MCU的低功耗模式。 FreeRTOS也提供了一个叫Tickless的低功耗模式,方便带FreeRTOS操作系统的应用开发 stm32的低…

C#创建obj三维模型文件

介绍 使用开源库创建obj三维模型文件。 开源库地址&#xff1a;https://github.com/JeremyAnsel/JeremyAnsel.Media.WavefrontObj 相关API地址&#xff1a;https://jeremyansel.github.io/JeremyAnsel.Media.WavefrontObj/api/JeremyAnsel.Media.WavefrontObj.ObjFile.html …

docker desktop实战部署oracle篇

1、前言 oracle数据库官方已提供现成的镜像&#xff0c;可以直接拿来部署了。 由于项目中需要使用oracle数据库的分表功能&#xff0c;之前安装的是standard版本&#xff0c;无奈只能重新安装。网上查了一番&#xff0c;使用的方法都比较传统老旧&#xff1a;下载安装包手动安…

多线程局部存储技术

问题 多线程上下文中&#xff0c;每个线程需要使用一个专属的全局变量&#xff0c;该如何实现&#xff1f; 代码示例 一种可能的解决方案 test1.c #define _GNU_SOURCE /* To get pthread_getattr_np() declaration */ #define _XOPEN_SOURCE > 500 || _POSIX_C_SOURC…

谷歌上架,为什么会触发填表单,可以避免吗?怎么填表单可以提高通过率?

在谷歌上架过程中&#xff0c;相信大部分开发者都有收到过谷歌发来表单填写的邮件通知&#xff0c;要求开发者们在14天内根据表单要求回复关于应用部分情况。邮件如图&#xff1a; 根据触发填表单的开发者分享的经验来看&#xff0c;填完表之后出现的情况不尽相同&#xff0c;且…

【华为】路由综合实验(OSPF+BGP基础)

【华为】路由综合实验 实验需求拓扑配置AR1AR2AR3AR4AR5PC1PC2 查看通信OSPF邻居OSPF路由表 BGPBGP邻居BGP 路由表 配置文档 实验需求 ① 自行规划IP地址 ② 在区域1里面 启用OSPF ③ 在区域1和区域2 启用BGP&#xff0c;使AR4和AR3成为eBGP&#xff0c;AR4和AR5成为iBGP对等体…

【JVM】class文件格式,JVM加载class文件流程,JVM运行时内存区域,对象分配内存流程

这篇文章本来只是想讲一下class文件格式&#xff0c;讲着讲着越讲越多。JVM这一块吧&#xff0c;知识比较散比较多&#xff0c;如果深研究下去如死扣《深入理解Java虚拟机》&#xff0c;这本书很深很细&#xff0c;全记住是不可能的&#xff0c;其实也没必要。趁这个机会直接把…

RK3568平台(基础篇)linux错误码

一.概述 linux应用程序开发过程中&#xff0c;经常会遇到一些错误信息的返回&#xff0c;存在的可能性有&#xff0c;参数有误、非法访问、系统资源限制、设备/文件不存在、访问权限限制等等。对于这类错误&#xff0c;可以通过perror函数输出具体描述&#xff0c;或者通过str…

nacos-server-1.2.1启动

1、双击startup.cmd 2、启动日志 3、访问http://192.168.26.210:8848/nacos/index.html 4、登录 用户名&#xff1a;nacos 密码&#xff1a;nacos

掌握JavaScript面向对象编程核心密码:深入解析JavaScript面向对象机制对象概念、原型模式与继承策略全面指南,高效创建高质量、可维护代码

ECMAScript&#xff08;简称ES&#xff0c;是JavaScript的标准规范&#xff09;支持面向对象编程&#xff0c;通过构造函数模拟类&#xff0c;原型链实现继承&#xff0c;以及ES6引入的class语法糖简化面向对象开发。对象可通过构造函数创建&#xff0c;使用原型链共享方法和属…

【云原生】Docker 的网络通信

Docker 的网络通信 1.Docker 容器网络通信的基本原理1.1 查看 Docker 容器网络1.2 宿主机与 Docker 容器建立网络通信的过程 2.使用命令查看 Docker 的网络配置信息3.Docker 的 4 种网络通信模式3.1 bridge 模式3.2 host 模式3.3 container 模式3.4 none 模式 4.容器间的通信4.…

小白如何搭建git

1、安装git 在Windows上安装git&#xff1a; 关注微信公众号“机器人学”回复 “搭建git” 利用百度云网盘下载安装包&#xff0c;建议下载如下版本的否则可能会出现错误。 安装完成后&#xff0c;在开始菜单里Git->git bash&#xff0c;弹出命令窗说明git安装成功。 鼠标右…

【Python项目】基于DJANGO的【基于语音识别的智能垃圾分类系统】

技术简介&#xff1a;使用Python技术、DJANGO框架、MYSQL数据库等实现。 系统简介&#xff1a;用户们可以在系统上面录入自己的个人信息&#xff0c;录入后还可以对信息进行修改&#xff0c;网站可以对用户上传的音频文件进行识别&#xff0c;然后进行垃圾分类。 背景&#xf…

【学习AI-相关路程-工具使用-自我学习-NVIDIA-cuda-工具安装 (1)】

【学习AI-相关路程-工具使用-自我学习-NVIDIA-cuda &#xff08;1&#xff09;】 1、前言2、环境配置1、对于jetson orin nx 的cuda环境2、对于Ubuntu 20.04下cuda环境 3、自我总结-安装流程1、在ubuntu下&#xff0c;如果想使用cuda平台&#xff0c;应该注意什么 和 都安装什么…

BGE向量模型架构和训练细节

模型论文&#xff1a;https://arxiv.org/pdf/2309.07597 模型数据&#xff1a;https://data.baai.ac.cn/details/BAAI-MTP 训练数据 由无标签数据和有标签数据组成。 无标签数据使用了悟道等数据集&#xff0c;有标签数据使用了dureader等数据集。 都是文本对&#xff0c;对于…

rust使用Atomic创建全局变量和使用

Mutex用起来简单&#xff0c;但是无法并发读&#xff0c;RwLock可以并发读&#xff0c;但是使用场景较为受限且性能不够&#xff0c;那么有没有一种全能性选手呢&#xff1f; 欢迎我们的Atomic闪亮登场。 从 Rust1.34 版本后&#xff0c;就正式支持原子类型。原子指的是一系列…

【redis】Redis数据类型(五)ZSet类型

目录 类型介绍特点补充 使用场景 Zset类型数据结构ziplist&#xff1a;压缩列表&#xff08;参考之前的文章&#xff09;skiplist&#xff1a;跳表解析 面试题&#xff1a;MySQL索引为什么用B树而不用跳表区别总结 常用命令ZADD示例 ZREM示例 ZCARD示例 ZCOUNT示例 ZSCORE示例 …

在线OJ——链表经典例题详解

引言&#xff1a;本篇博客详细讲解了关于链表的三个经典例题&#xff0c;分别是&#xff1a;环形链表&#xff08;简单&#xff09;&#xff0c;环形链表Ⅱ&#xff08;中等&#xff09;&#xff0c;随机链表的复制&#xff08;中等&#xff09;。当你能毫无压力地听懂和成功地…
最新文章