Vue.js 比较重要知识点总结四

news2024/11/24 12:24:06

概述

  • ref toRef toRefs进阶,深入理解
  • vue3 setup
  • Vue3为何比Vue2快?
  • 怎样理解 Vue 的单向数据流?
  • Vue 中事件绑定原理
  • vue3 mitt 使用

ref toRef toRefs进阶,深入理解

  1. 为何需要ref?

    1. 返回值类型,会丢失响应式
    2. setup、computed、合成函数,都有可能返回值类型
    3. Vue如果不定义ref,用户将自定义ref,反而混乱
  2. 为何需要.value?

    1. ref是一个对象(不丢失响应式),value存储值
    2. 通过.value属性的get和set实现响应式
    3. 用于模板、reactive时,不需要.value,其他情况都需要
  3. 为何需要toRef toRefs

    1. 初衷:不丢失响应式的情况下,把对象数据进行分解和扩散
    2. 前提:针对的事响应式对象,不是普通对象
    3. 注意:不创造响应式,而是延续响应式

更多精彩内容,请微信搜索“前端爱好者戳我 查看

vue3 setup

script setup 是干啥的?

scrtpt setup 是 vue3 的语法糖,简化了组合式 API 的写法,并且运行性能更好。

使用 script setup 语法糖的特点:

  • 属性和方法无需返回,可以直接使用。
  • 引入组件的时候,会自动注册,无需通过 components 手动注册。
  • 使用 defineProps 接收父组件传递的值。
  • useAttrs 获取属性,useSlots 获取插槽,defineEmits 获取自定义事件。
  • 默认不会对外暴露任何属性,如果有需要可使用 defineExpose 。

setup中如何获取组件实例?

  • setup和其他Composition API中都没有this
  • 在Options API中仍然可以使用this
  • Composition API中可以使用 getCurrentInstance 方法获取

vue3 getCurrentInstance

Vue2中,可以通过this来获取当前组件实例;

Vue3中,在setup中无法通过this获取组件实例,console.log(this)打印出来的值是undefined。

在Vue3中,getCurrentInstance()可以用来获取当前组件实例 vue3官方文档解释

let { proxy } = getCurrentInstance();

在setup中分别打印下面3个值,结果如下:

console.log(getCurrentInstance,typeof(getCurrentInstance));
console.log(getCurrentInstance(),typeof(getCurrentInstance()));
console.log(proxy,typeof(proxy));

结果

可以看到:

  • getCurrentInstance是一个function方法,
  • getCurrentInstance()是一个对象,proxy也是一个对象。
  • proxy是getCurrentInstance()对象中的一个属性,通过对象的解构赋值方式拿到proxy。

getCurrentInstance只能在setup生命周期钩子中使用。

在onMunted生命周期中打印getCurrentInstance

定义一个test方法,通过click事件触发方法

onMounted(() => {
  console.log(getCurrentInstance(), typeof getCurrentInstance());
});
function test() {
  console.log(getCurrentInstance(), typeof getCurrentInstance());
}

可以看到在function中是无法获取该实例的。

let { ctx } = getCurrentInstance();
console.log(ctx, typeof ctx);
let { proxy } = getCurrentInstance();
console.log(proxy, typeof proxy);

ctx和proxy都是getCurrentInstance()对象中的属性,通过解构赋值的方式拿到。可以看到,2者有所区别。

ctx是普通对象,proxy是Proxy对象。

补充:Vue3中关于getCurrentInstance的大坑

开发中只适用于调试! 不要用于线上环境,否则会有问题!

解决方案:

方案1.

获取挂载到全局中的方法

const instance = getCurrentInstance()
console.log(instance.appContext.config.globalProperties)

方案2.

使用proxy线上也不会出现问题

const { proxy } = getCurrentInstance()  

Vue3为何比Vue2快?

  1. Proxy实现响应式
  2. patchFlag https://vue-next-template-explorer.netlify.app/
    1. 编译模板时,动态节点做标记
    2. 标记,分为不同的类型,如TEXT,PROPS
    3. diff时,区分静态节点和不同类型的动态节点
  3. hoistStatic
    1. 将静态节点的定义,提升到父作用域,缓存起来,空间换时间
    2. 多个相邻的静态节点,会被合并起来,编译优化
  4. cacheHandler
    缓存事件
  5. SSR优化
    静态节点直接输出为dom,绕过vdom
  6. tree-shaking
    编译时,按需引入API

怎样理解 Vue 的单向数据流?

所有的 prop 都使得其父子 prop 之间形成了 一个单向下行 绑定:

父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。

如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

有两种常⻅的试图改变一个 prop 的情形 :

这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用

在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:

props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}

这个 prop 以一种原始的值传入且需要进行转换

在这种情况下,最好使用这个 prop 的值来定义 一个计算属性

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

Vue 中事件绑定原理

$emit

vm.$emit('事件名称', 可选参数)

触发当前实例上的事件,要传递的数据会传给监听器;

$on

vm.$on('事件名称', callback) callback回调emit要传送的数据

监听当前实例上自定义事件;

$off

vm.$off( [event, callback] )

移除自定义事件监听器。

  • 如果没有提供参数,则移除所有的事件监听器;
  • 如果只提供了事件,则移除该事件所有的监听器;
  • 如果同时提供了事件与回调,则只移除这个回调的监听器。

vue2 使用例子

//父组件
<template>
  <ratingselect @select-type="onSelectType"></ratingselect>
</template>
<script>
  data () {
   return {
    selectType: 0,
  },
  methods: {
   onSelectType (type) {
    this.selectType = type
   }
  }
</script>

父组件使用@select-type=“onSelectType”@就是v-on的简写,监听由子组件vm.$emit触发的事件,通过onSelectType()接受从子组件传递过来的数据,通知父组件数据改变了。

// 子组件
<template>
 <div>
  <span @click="select(0, $event)" :class="{'active': selectType===0}"></span>
  <span @click="select(1, $event)" :class="{'active': selectType===1}"></span>
  <span @click="select(2, $event)" :class="{'active': selectType===2}"></span>
 </div>
</template>
<script>
  data () {
   return {
    selectType: 0,
  },
  methods: {
    select (type, event) {
      this.selectType = type
      this.$emit('select-type', type)
   }
  }
</script>

子组件通过$emit来触发事件,将参数传递出去。

vue3 使用例子 – Vue3.x推荐使用外部库mitt来代替 $on $emit $off

mitt源码使用的是typescript编写的,源码加注释一共不到90行,阅读起来比较轻松。

typescript不是本次的重点,所以将mitt源码以js的形式展示如下。

/**
 * 向外暴露的默认函数
 * @param 入参为 EventHandlerMap 对象 (ts真香,我们能清楚的知道参数的类型是什么,返回值是什么)
 * @returns 返回一个对象,对象包含属性 all,方法 on,off,emit
 */
export default function mitt (all) {
  /*
    此处实参可传一个EventHandlerMap对象,实现多个 mitt 的合并。例如:
    const m1 = mitt();
    m1.on('hi', () => { console.log('Hi, I am belongs to m1.'); });

    const m2 = mitt(m1.all);
    m2.emit('hi') // Hi, I am belongs to m1.
    m2.on('hello', () => { console.log('Hello, I am belongs to m2.'); });

    m1.emit('hello'); // Hello, I am belongs to m2.

    m1.all === m2.all // true
  */
  all = all || new Map();

  return {
    // 事件键值对映射对象
    all,

    /**
     * 注册一个命名的事件处理
     * @param type 事件名,官方表示事件名如是 *,用来标记为通用事件,调用任何事件,都会触发命名为 * 的事件
     * @param handler 事件处理函数
     */
    on (type, handler) {
      // 根据type去查找事件
      const handlers = all.get(type);
      // 如果找到有相同的事件,则继续添加,Array.prototype.push 返回值为添加后的新长度,
      const added = handlers && handlers.push(handler);
      // 如果已添加了type事件,则不再执行set操作
      if (!added) {
        all.set(type, [handler]); // 注意此处值是数组类型,可以添加多个相同的事件
      }
    },

    /**
     * 移除指定的事件处理
     * @param type 事件名,和第二个参数一起用来移除指定的事件,
     * @param handler 事件处理函数
     */
    off (type, handler) {
      // 根据type去查找事件
      const handlers = all.get(type);
      // 如果找到则进行删除操作
      if (handlers) {
        // 这里用了个骚操作,其实就是找到了,则删除(多个相同的只会删除找到的第一个),没找到则不会对原数组有任何影响
        handlers.splice(handlers.indexOf(handler) >>> 0, 1);
      }
    },

    /**
     * 触发所有 type 事件,如果有type为 * 的事件,则最后会执行。
     * @param type 事件名
     * @param evt 传递给处理函数的参数
     */
    emit (type, evt) {
      // 找到type的事件循环执行
      (all.get(type) || []).slice().map((handler) => { handler(evt); });
      // 然后找到所有为*的事件,循环执行
      (all.get('*') || []).slice().map((handler) => { handler(type, evt); });
    }
  };
}

vue3 mitt 使用

mitt优势

  • 首先它足够小,仅有200bytes。
  • 其次支持全部事件的监听和批量移除。
  • 它还不依赖 Vue 实例,可以跨框架使用,React 或者 Vue,甚至 jQuery 项目都能使用同一套库。

API

// 创建mitt实例
mitt()

// 事件名称到注册处理程序函数的映射。
all

//触发事件,两个参数:name:触发的方法名,data:需要传递的参数
emit(name,data) 

// 绑定事件,两个参数:name:绑定的方法名,callback:触发后执行的回调函数
on(name,callback) 

// 解绑事件,一个参数:name:需要解绑的方法名
off(name)  

安装mitt:

npm install mitt -save

新建EventBus.js文件:

// 事件总线第三方库:
import mitt from 'mitt';
const bus = mitt();
export default bus;

案例使用

发出事件的页面:send.vue

<template>
    <div class="box">
        <h2>send页面视图</h2>
        <button @click="sendData">局部事件总线:点击之后给cc页面传递一个值</button>
    </div>
    
</template>
 
<script setup>
import bus from "../utils/EventBus" 
const sendData = () => {
  bus.emit("data",18)
}
</script> 

接收事件的页面:response.vue

<template>
    <div>
        <h2>response页面视图</h2>
    </div>
</template>
 
<script setup>
import bus from "../utils/EventBus"
import { ref ,onMounted} from "vue";
onMounted(()=>{
    bus.on("data",(info)=>{
      // info 就是emit传过来的数据
      console.log("dd页面接收到的值:",info)
    })
}) 
</script>

移除监听事件

Bus.off('Event');

参考地址:

  • https://tangjiusheng.com/web/4935.html
  • https://blog.csdn.net/weixin_41759744/article/details/125305021
  • https://www.jb51.net/article/263720.htm

前端爱好者

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【常用设计模式】待补充

Github仓库地址 概述 23中设计模型分为常见的三大类&#xff1a;创建型模式、结构型模式和行为型模式 创建型模式 简单工厂模式 描述 简单工厂模式不是23中设计模式中的。简单工厂模式不直接向客户端暴露对象创建的细节&#xff0c;而是通过一个工厂类来负责创建产品类的实…

12.MSP432E4 Keil烧录报错Error Flash Download failed - Cortex-M4

一、简介 前段时间琢磨了一块新板子&#xff0c;ESP432E401Y。 遇到一个问题&#xff0c;简单记录一下&#xff0c;问题是在keil中正常烧录程序后&#xff0c;在CCS下也烧录了一次程序&#xff0c;然后就一直无法再到keil中烧录&#xff0c;但是CCS一直是正常烧录的。keil报错…

Spark集群搭建

系列文章目录 Ubuntu常见基本问题 Hadoop3.1.3安装&#xff08;单机、伪分布&#xff09; Hadoop集群搭建 HBase2.2.2安装&#xff08;单机、伪分布&#xff09; Zookeeper集群搭建 HBase集群搭建 Spark安装和编程实践&#xff08;Spark2.4.0&#xff09; Spark集群搭建 文章目…

linux开发:linux最大线程数分析

linux最大线程数分为&#xff0c;进程最大线程数&#xff0c;用户最大进程数&#xff0c; 整个系统已用的线程或进程数。 我们可以用下面命令进行查询这三个进程数。 linux系统可生成最大线程数可以用这个命令查询 cat /proc/sys/kernel/threads-max 进程最大线程数查询方式 ps…

家用儿童帆布床出口欧盟CE认证EN716测试

1.标准适用范围 该标准规定了内部长度大于900mm但不超过1400mm的家用童床的安全要求。该安全要求适用于完全组装完毕待用的童床。可以转换成其它产品的童床&#xff08;如&#xff1a;可变产品、游戏床&#xff09;转换后应该符合相关欧洲标准。该标准不适用于提篮、婴儿床和摇…

hacknet攻略(更新中)

序章 然后点自己的电脑&#xff0c;再点一下SCAN(扫描可用主机)&#xff0c;再点断开 然后点蓝色的电脑&#xff0c;是连接的意思 点中间Probe系统图标&#xff0c;看开放端口数 若端口数为0可以使用porthakc命令直接黑入系统 几个会用到的命令cd, rm * ,dc关闭连接&…

Unity制作二次元卡通渲染角色材质——4 、内外描边和细节添加

Unity制作二次元材质角色 回到目录 大家好&#xff0c;我是阿赵。 这里继续讲二次元角色材质。这次打算讲一下描边和细节的添加。 一、外描边 外描边的做法也不止一种&#xff0c;比如后处理方法的偏导数ddx/ddy之类的&#xff0c;也能整个屏幕的求出边缘。但一般来说单模型渲…

MySQL数据库学习笔记(九)实验课六之触发器和存储过程

没想到这就是最后一次实验了。 一点知识&#xff1a; 道具 – delimiter / DELIMITER 这是用于指定语句分隔符的特殊命令 默认情况下&#xff0c;MySQL使用分号&#xff08;;&#xff09;作为语句的结束符。然而&#xff0c;当我们需要定义存储过程、触发器或函数等包含多条S…

51智能小车-串口控制、循迹、避障

目录 1.串口控制小车 2.循迹小车 3.避障小车 1.串口控制小车 L9110s概述 接通VCC&#xff0c;GND 模块电源指示灯亮&#xff0c; 以下资料来源官方&#xff0c;但是不对&#xff0c;根据下节课实际调试 IA1输入高电平&#xff0c;IA1输入低电平&#xff0c;【OA1 OB1】电机…

总结890

学习目标&#xff1a; 月目标&#xff1a;6月&#xff08;线性代数强化9讲2遍&#xff0c;背诵15篇短文&#xff0c;考研核心词过三遍&#xff09; 周目标&#xff1a;线性代数强化3讲&#xff0c;英语背3篇文章并回诵&#xff0c;检测 每日必复习&#xff08;5分钟&#xff…

STM32开发——简介、开发环境(Keil5、CubeMX)、HAL库

目录 1.简介-初识STM32 2.开发环境 2.1使用Keil5 2.2使用STM32CubeMX 3.标准库与HAL库区别 4.推挽输出与开漏输出 1.简介-初识STM32 什么是单片机&#xff1f; 单片机&#xff08;Single-Chip Microcomputer&#xff09;是一种集成电路芯片&#xff0c;把具有数据处理能…

kafka部分面试常见问题及其解答(接上)

16. kafka创建Topic时如何将分区分配给各Broker 副本因子不能大于 Broker 的个数&#xff1b;第1个分区&#xff08;partition_0&#xff09;的第1个副本放置位置是随机从brokerList选择的&#xff1b;其他分区的第一个副本放置位置相对于partition_0依次往后移。 如果我们有5…

vue 3 第三十二章:状态管理(Pinia状态持久化)

Pinia 的状态持久化 在实际开发中&#xff0c;我们通常需要对状态进行持久化或缓存&#xff0c;以便在应用程序重新加载或离线时仍然能够访问数据。在 Pinia 中&#xff0c;我们可以使用插件来实现状态的持久化和数据缓存。 Pinia 提供了一个名为pinia-plugin-persist的插件&…

Linux - 文件操作和系统接口

​​​​​​​ 感谢各位 点赞 收藏 评论 三连支持 本文章收录于专栏【Linux系统编程】 ❀希望能对大家有所帮助❀ 本文章由 风君子吖 原创 ​​​​​​​ ​​​​​​​ ​​​​​​​ ​ 前言 对于文件操作&#xff0c;不知大家是否有过接…

永恒之黑漏洞复现

一、实验环境搭建 系统镜像&#xff1a; ed2k://|file|cn_windows_10_consumer_editions_version_1903_x64_dvd_8f05241d.iso|4905476096|F28FDC23DA34D55BA466BFD6E91DD311|/ 建议使用迅雷下载,安装版本选win10专业版 安装完后记得一定要关闭defender&#xff0c;防火墙&…

配置主机加入已有 tinc 集群简明过程

文章目录 Cent OS服务器安装tinc配置文件过程中使用到的一些Linux命令小记 启动tinc开放端口 Windows主机参考资料 本文的主要内容是如何将主机加入已有的 tinc 集群。 Cent OS服务器 安装tinc yum install tinc如果不先 su 到 root 账户的话&#xff0c;可能会无法安装。 因…

Python模块os 操作系统

目录 1. 系统类 --------------------- 解释器 --------------------- system 执行系统命令 wait 等待任意子进程 waitpid 等待指定的子进程 kill 指定杀死进程 abort 立即中止解释器 pipe 管道操作 --------------------- 随机字符 --------------------- urandom …

KMeans+DBSCAN密度聚类+层次聚类的使用(附案例实战)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

数据结构之栈、队列——算法与数据结构入门笔记(四)

本文是算法与数据结构的学习笔记第四篇&#xff0c;将持续更新&#xff0c;欢迎小伙伴们阅读学习 。有不懂的或错误的地方&#xff0c;欢迎交流 栈 栈是一种线性数据结构&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶 (Top&…

虚幻5-编辑器扩展开发Editor-Slate的TabManager结构如下

目录 Editor-Slate WorkSpaceMenu(Slate相关类) Editor-Tab-界面刷新 Editor-Slate 基本上&#xff0c;地球人都知道&#xff08;我不是地球人&#xff09;虚幻引擎的Editor界面&#xff08;自定义&#xff09;通过Slate管理 Slate的入口是方法&#xff1a;&#xff1a;Co…