在Vue.js中应该避免的三件事

news/2024/3/29 10:05:52/文章来源:https://blog.csdn.net/nsrainbow/article/details/124295081

1. 尽量避免使用行内事件代码(inline script)

这是一个行内事件代码 的例子

<div @click="alert('hello world'); doSomething();" />

这种代码虽然第一次写起来很简单,但是很容易出bug。这样做有两个缺点。

VS Code 无法检查行内事件代码的错误

VS Code没有办法帮你检查模板中的行内事件代码,所以请尽量不要写行内事件代码。你可能会觉得有些代码很简单,你可以直接看出有没有错误。但实际上,大多数时间我们都看不出一些简单的错误。比如我们在模板中有两句简单的代码

<div @click="alert('hello world'); doSomething();" />

以下是其中一行代码doSomething() 的定义

doSomething(event: Event) {// do something ...
}

VS Code不会给你提示任何的错误。但是如果你运行这些代码,你会发现doSomethingevent 对象是undefined。原因很简单,因为我们在模板中写的是doSomething()。如果你不用行内事件代码,而是把需要处理的逻辑全部抽取到一个事件处理方法里面。 把所有的js逻辑放到一个统一的地方,情况就不一样了。比如我们把事件处理逻辑移到sayHelloAndDoSomething 方法中

sayHelloAndDoSomething() {console.log('do something');this.doSomething();
}

这回VS Code就发现了你的错误。VS Code帮你发现了doSomething 需要一个必须的参数 event
在这里插入图片描述
使用行内事件代码更糟糕的是它看起来可以运行,有的时候真的可以运行,只不过有一些不会引发代码崩溃的bug被隐藏了起来。虽然上面这个例子看起来很简单,但是在实际工作中,我经常可以看到类似的错误。

使用行内事件代码会给生产环境调试造成困难

由于在生产环境上的代码多半是被混淆和压缩过的,如果你没有使用Sourcemap。当生产环境出现问题时,当你打开浏览器的调试工具想通过调试来排查问题的时候,你会发现编译后的html文件是一个很长的单行代码。你根本没有办法往里面加断点来调试。但是如果你把代码放到一个方法里面,你还是可以使用浏览器的调试工具来加断点。

2. 尽量避免使用侦听属性

Vue.js 的官方文档已经明确建议大家使用侦听属性之前请三思。
在这里插入图片描述
为什么侦听属性不好呢?因为侦听属性其实是一种隐式依赖。

什么是隐式依赖

当一个组件或者方法明确的调用另外一个组件或者方法的时候,我们称之为显式依赖。比如

class Foo {getName: () {return "Terry";}
}
class Bar {sayHello: () {const foo = new Foo();retur "Hello! " + foo.getName();}
}

在这个例子中 Foo.getNameBar.sayHello 之间有明确的现实依赖。当输出有问题的时候,你知道去哪里找问题。如果你使用了IDE,当你点击foo.getName()的时候,你会自动跳转到 getName 的定义代码。

隐式依赖跟显示依赖相对,在这种关系中的两个组件或者方法之间往往没有明确的关联关系。你通过IDE的自动关联功能是无法自动关联上它们的。你需要使用搜索功能来找到这些代码之间的关联。

可能很多人很痛很基于事件总线的观察者模式。我曾经有一个领导说他再也不想用事件总线了。我以前也开发过基于事件总线的代码。当你在调试的时候,代码总是在项目的各个角落来回跳转,有时候你根本不知道哪一个代码会被某一个监听器触发。有的时候各个监听器触发的代码的结果会互相覆盖。基于事件总线的观察者模式最大的问题就在于隐式依赖。那些散落在项目各处的监听器代码事件广播代码之间的关系就是隐式依赖。比如
在A.js中你可以广播一个事件

this.$bus.sendEvent('sayHello')

然后在 B.js和C.js中都可以监听这个事件
B.js

this.$bus.listenEvent('sayHello', function() {console.log("I'm B. I got hello!")
})

C.js

this.$bus.listenEvent('sayHello', function() {console.log("I'm C. I got hello!")
})

当事件被广播的时候你无法控制被触发的代码的执行顺序,你甚至都不知道有多少处代码被触发了。最可怕的是当你改动了事件的广播代码的时候,你不知道哪个部分的代码被你破坏了。因为你很容易漏改某个逻辑。

侦听属性(Watcher)的地雷

此外,侦听属性本身还有两个初学者容易踩的雷:

  1. 侦听属性默认是懒加载(lazy loading)的。所以当组建被第一次创建时,它不会被触发。所以如果你有一些代码既想在组建初始化时被运行,又想当某些属性变化时被触发,你就必须在created 或者 mounted 中写一遍,并且在侦听属性中再写一遍。你也可以给侦听属性加上immediate: true 属性,这样侦听属性就会在组建创建的时候被执行一次。但是这样做可能容易出现死循环。
  2. 侦听属性是不能被暂停的。你可以销毁它或者根据Evan在这个回答中所说的一样,增加一个变量来达到在某些情况下跳过侦听属性内部的逻辑的效果。我在使用侦听属性的时候,会增加一个变量watcherEnabled 来在某些情况下关闭侦听属性。但是这个属性也给我带来了很多麻烦。有些bug就是因为没有及时改变这个属性的值造成的。而且对于模板渲染来说,你在同一个tick 中对一个变量多次赋值,它并不会多次渲染。比如,如果你在同一个tick 中先把watcherEnable 赋值为true ,然后赋值为false,最后再赋值为true,对于模版渲染来说,这个值等于没变。所以我必须用 vue.nextTick 来让模板"感受"到这个值的变化。

比侦听属性(Watcher)更好的方式

以下是5种比侦听属性(Watcher)更好的方式。

从子组件到父组件

如果是想让子组件调用父组件的方法,我们可以使用:自定义事件。通过使用自定义事件,子组件可以通知父组件调用指定的方法。

在这里插入图片描述

从父组件到子组件

如果你想让父组件调用子组件的方法或者让子组件的某些属性更新。如果要触发的方法在子方法中。与其使用$refs,不如将该方法移动到父组件。然后,您可以直接调用它或使用自定义事件
在这里插入图片描述

使用ref属性

如果您想触发的方法不能移动到父方法。或者您不想冒险重构任务。你可以使用ref属性
在这里插入图片描述
但是请记住,使用$refs并不是一个好的实践。$refs也有自己的问题。组件$refs在呈现时是未定义的。所以如果你在模板中使用$refs,它可能没有值。如果你使用$refs,computed有可能会坏掉。这是一个使用computed来获取子组件scrollLeft属性的例子。

get childScollLeft() {return this.$refs.child.scrollLeft;
}

这个computed其实不会有用。因为当你想要在computed中观察的变量在开始时是未定义的,那么这个computed就会失去响应性。就算$refs加载之后,它也不会生效。

使用props

如果你想更新子组件UI。你可以使用props
在这里插入图片描述

从任何地方

使用 Vuex或者Pinia

如果你想更新父/子/兄弟组件UI。你可以使用Vuex或者Pinia。唯一的缺点是这可能会增加代码的复杂性。
在这里插入图片描述

3. 不要通过props传递函数

在Vue.js中用props传递函数是一个反模式中有一句话非常好。

随着应用程序的规模越来越大,其他开发人员加入,他们将查看子组件代码,并必须弄清楚它是哪个prop引入了这个函数以及这个函数来自哪里。

这就是我在自己项目中遇到的问题。有时我需要弄清楚这些方法是从哪里来的。我非常同意他的观点。但这并不是我不建议将函数作为props传递的主要原因。主要原因是,当我阅读代码时,需要花费一些精力来熟悉这个组件的上下文。如果有一个函数作为prop传递,那么我需要熟悉另一个组件的上下文。如果仅仅是这样,其实也没那么糟。更糟糕的是,当阅读代码时,我还需要在不同的组件上下文之间来回切换。

如果你想传递函数,我建议使用自定义事件,而不是通过prop传递函数。

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

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

相关文章

移动WEB开发五、响应式布局

零、文章目录 文章地址 个人博客-CSDN地址&#xff1a;https://blog.csdn.net/liyou123456789个人博客-GiteePages&#xff1a;https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee&#xff1a;https://gitee.com/bluecusliyou/TechLearnGithub&#xff1a;https:…

Dubbo之SpringBoot启动源码详解

需要前置知识&#xff0c;了解spring源码&#xff0c;springboot自动加载机制等 DubboBootstrap启动 详细信息可看 学习Dubbo源码需要了解的基础内容源码详解 DubboBootstrap 启动所需要的信息 添加应用程序配置添加注册中心配置添加协议配置添加服务配置启动 SpringBoot启…

音视频基础之音频编码原理简介

一&#xff1a;隐蔽信号 数字音频信号如果不加压缩地直接进行传送&#xff0c;将会占用极大的带宽。例如&#xff0c;一套双声道数字音频若取样频率为44.1KHz&#xff0c;每样值按16bit量化&#xff0c;则其码率为&#xff1a; 244.1kHz16bit1.411Mbit/s 如此大的带宽将给信号…

电商数据查询平台:母婴行业妈妈用品全网热销,头部品牌格局初现

以往&#xff0c;奶粉、纸尿裤这类产品基本就代表了整体母婴市场中的消费品。而如今&#xff0c;随着母婴行业的高速发展和消费升级&#xff0c;母婴商品的种类日益丰富&#xff0c;需求也不断深入。 在京东平台&#xff0c;母婴大品类中除了包含婴童相关的食品&#xff08;奶粉…

2022爱分析·事务型关系数据库市场厂商评估报告:万里数据库

目录 1. 研究范围定义 2. 事务型关系数据库市场定义 3. 厂商评估&#xff1a;万里数据库 4. 入选证书 1. 研究范围定义 在国内数字化转型以及信创建设持续推进的大背景下&#xff0c;众多厂商入局国内数据库市场&#xff0c;为企业提供了面向多种应用场景的数据库&am…

「7」线性代数(期末复习)

&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680; 目录 第五章 相似矩阵及二次型 &4&#xff09;对称阵的对角化 &5二次型及其标准型 …

《mysql技术内幕:innodb存储引擎》笔记

任何时候Why都比What重要&#xff1b;不要相信任何的“神话”,学会自己思考&#xff1b;不要墨守成规,大部分人都知道的事情可能是错误的&#xff1b;不要相信网上的传言,去测试,根据自己的实践做出决定&#xff1b;花时间充分地思考,敢于提出质疑。1.MYSQL被设计为一个单进程多…

Elasticsearch也能“分库分表“,rollover实现自动分索引

一、自动创建新索引的方法 MySQL的分库分表大家是非常熟悉的&#xff0c;在Elasticserach中有存在类似的场景需求。为了不让单个索引太过于庞大&#xff0c;从而引发性能变差等问题&#xff0c;我们常常有根据索引大小、时间等创建新索引的需求&#xff0c;解决方案一般有两个…

虚拟 DOM 详解

什么是虚拟 dom&#xff1f; 虚拟 dom 本质上就是一个普通的 JS 对象&#xff0c;用于描述视图的界面结构 在vue中&#xff0c;每个组件都有一个render函数&#xff0c;每个render函数都会返回一个虚拟 dom 树&#xff0c;这也就意味着每个组件都对应一棵虚拟 DOM 树 查看虚拟…

C#中多态、抽象类、虚方法

多态、重装、重写 •多态&#xff1a;同一操作作用于不同的对象&#xff0c;可以有不同的解释&#xff0c;产生不同的执行结果&#xff0c;这就是多态性。抽象类、虚函数、接口三种方法实现的可以是多态性。•重载&#xff08;overload&#xff09;&#xff1a;对象中同名函数&…

JSP 质量管理系统myeclipse定制开发sqlserver数据库网页模式java编程jdbc

一、源码特点 JSP 质量管理系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开 发&#xff0c;数据库为SQLServer2008&#xff0c…

二、最基本的vuex的使用

二、最基本的vuex的使用&#xff1a; 学习任何技术&#xff0c;先找到没有用这个技术时&#xff0c;给我们带来了什么麻烦 而这个新技术是怎么帮我们解决这些问题的。 理解方式&#xff1a; state&#xff1a;装数据的一个对象 mutations&#xff1a;装方法的一个对象&#…

hydra常见端口服务穷举

目录 工具介绍 参数说明 官方示例 官方字典 ssh爆破 ftp爆破 mysql爆破 smb爆破 rdb爆破 http爆破 redis爆破 工具介绍 hydra 是一个支持众多协议的爆破工具&#xff0c;已经集成到KaliLinux中&#xff0c;直接在终端打开即可 参数说明 -l &#xff1a; 指定破…

mybatis狂神(附自学过程中疑问解决)

首先先附上mybatis的官方文本链接mybatis – MyBatis 3 | 简介一、Mybatis介绍MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来…

RK3288 GPIO记录

1、引脚对应的GPIO 编号第一种 使用/sys/kernel/debug/gpio查询所有gpio引脚的基数第二种 cat /sys/class/gpio/gpiochip248/label对应的label就是GPIO引脚&#xff0c;例如下图GPIO8对应的基数就是2482、计算编号编号 基数 PIN脚如GPIO8的基数是248&#xff0c; GPIO8_A6的编…

django项目实战三(django+bootstrap实现增删改查)进阶分页

目录 一、分页 1、修改case_list.html页面 2、修改views.py的case_list方法&#xff08;分页未封装&#xff09; 二、分页封装 1、新建类Pagination 2、修改views.py的case_list方法 三、再优化&#xff0c;实现搜索分页qing情况 四、优化其他查询页面实现分页和查询 五…

MySQL —— 内外连接

目录 表的内外连接 一、内连接 二、外连接 1. 左外连接 2. 右外连接 表的内外连接 表的连接分为内连和外连 一、内连接 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选&#xff0c;我们前面博客中的查询都是内连接&#xff0c;也是在开发过程中使用的最多…

Java面试题--熔断和降级的区别

熔断和降级都是系统自我保护的一种机制&#xff0c;但二者又有所不同&#xff0c;它们的区别主要体现在以下几点&#xff1a; 概念不同 触发条件不同 归属关系不同 1.概念不同 1.1熔断概念 “熔断”一词早期来自股票市场。熔断&#xff08;Circuit Breaker&#xff09;也…

JavaWab开发的总括以及HTML知识

一、Web开发的总括在这里我来给大家介绍一下Wab开发需要配合哪些前后端的对应语言:首先是Java(Java通常的工作):Wab开发android开发大数据开发另外,Wab开发想要学好就需要配合之前博客中的内容,如:多线程/IO/网络/数据结构/数据库......这里建议学懂前面的内容再往下走.JavaWab…

Python采集双色球数据,做数据分析,让我自己实现自己的富豪梦

来唠点嗑&#xff1f; 咳咳&#xff0c;最近是咋的了&#xff0c;某站掀起了一股双色球热潮&#xff1f;一般我自己的账号上&#xff0c;是很少看到关于python这些内容的&#xff0c;都是小姐姐和热梗&#xff0c;或者其他搞笑视频 由于&#x1f4b4;的吸引力…手不自觉的就点…