vue 问题整合

5 篇文章 1 订阅

vue 问题整合

本文主要整合了自己在平常开发过程中遇到的一些vue相关的问题的总结


2020/04/19 add生命周期钩子函数


2020/04/20 add混入


2020/04/21 add 环境变量


2020/04/22 add 动态组件component


2020/05/06 add vuex使用


2020/05/28 add vue css scoped module


2020/06/01 add vue 行内样式设置 hover


2020/06/02 add media Query


2020/07/07 add vue data 新增 property 响应式


2020/07/28 add html 属性,使用 target 控制地址跳转


2020/08/10 add vue-cli + webpack configure


2020/08/10 add vue-cli + webpack configure


2020/09/15 add v-model vs :value and on-change


2020/11/04 add vue beforeRouteEnter beforeRouteleave


2020/12/12 add Vue.set this,$set


2020/12/20 add :title 与 tooltip


2021/02/10 add watch 介绍


2021/03/22 add process.env


2021/07/12 add props 与表单结合


2021/08/06 add vue 初始化顺序


2021/08/06 add vue 注入全局变量


2021/08/15 从 code review 中获得的经验


2021/08/18 add vue-router


2021/10/11 add eventBus vs vuex


2021/10/14 add vue3 学习之 composition API vs options API


2021/12/05 add vue 修改数据


2021/12/05 add vue 语言国际化


2022/01/15 add vue why app.js is so big


vue 组件代码规范

name
components
props
data
computed
watch
created
beforeDestroy
methods

process.env

我们可以修改环境变量,通过这种方式对不同环境的显示进行开关控制,开发中发现可以在 data(){} computed 中读取 process.env 但在模板中无法取到,这是什么原因呢?

Environment Variables

vue-cli-service serve does not set process.env.NODE_ENV, or any environmental variables. “process is not defined”. #1128

vue-cli是什么?和 webpack是什么关系?

如上我们知道 NODE_ENV, BASE_URL, and variables that start with VUE_APP_ will be statically embedded into the client bundle with webpack.DefinePlugin 但事实上文档中并未标明只能在 js 中使用,无法在模板中使用,因此如果想在模板中直接使用 process.env 需要做一个 hack 将其挂载在实例属性上即可

// main.js
Vue.prototype.process = Object.freeze({
  env: process.env,
})

vue-router

一个网站可能不能在一个项目完成所有的开发,我们让多个项目衔接起来的方式可以通过 NGINX 配置完成,同时每个项目都是一个 SPA。在开发中遇到了一个问题:在 A 项目中想使用 $router.push 跳转到 B 项目的路由下,以失败告终。

Vue.js redirection to another page

MDN History

Configuring Vue Router for a Single Page App

$router的由来实际上就是 html5 history api, 它的出现为单页应用的出现提供了基石,因此如果想实现从 A 项目路由跳转到 B 项目的路由直接使用 location.href 即可。

Vue 全局变量注入

官方文档不再赘述:
https://cn.vuejs.org/v2/cookbook/adding-instance-properties.html

上一个 case 中我们 hack 了 process.env 让它能够在模板中使用,这一点其实不推荐毕竟官方没这么做。

watch 介绍

我们知道 watch 可以监听属性的变化,如 data 中的属性,state 中的值,在开发中有些场景发现 watch 无法监控到这些值的变化,是因为什么呢?

references:

vue watch监听不到对象,探究 watch 原理

watch监听不到路由的变化

watch 不起作用的原因

  1. 监控了原对象上不包含的属性

vue的绑定原理是建立在Object.defineProperty的set和get方法上的。给某个属性绑定set和get之后,只有改变该属性本身时,才会触发set和get的回调函数,而改变其内部属性时不会触发。

但实际上这个问题有解决方法就是添加 deep 参数即可。

  1. 组件已经被销毁,自然监听不到值的变化。

比如我的 case 里面就是由于加入了一个 loading 变量,而由于 v-if v-else 的使用导致组件重新被 mount 出现了监听不到预期的值的现象

:title 与 tooltip

当然 title 并不是 Vue 的特性,而是 html 标签的特性。其实 title 的表现效果就是如 tooltip 一般,但就是反应较慢,但鉴于使用方便,此处给予记录。(从代码优雅性上看还是用 tooltip 组件更好

了解HTML标签元素中alt和title属性的区别

Vue v-bind $attr

禁用 Attribute 继承

特别适用于写基础组件时,这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素,而不会担心哪个元素是真正的根元素

Vue beforeRouteEnter beforeRouteleave

最近做需求有这样一个场景,进入一个页面启动一个 setTimeout,离开此路由后就停用 timer,显然 vue-router 中的 beforeRouteLeave 可以满足这个场景。同时它也可以用于在用户离开服务前是否提醒其进行保存等,而保存的内容
有以下几种方式进行存储: localStorage 或直接传给后端存储。

同时遇到这样一个 beforeRouteLeave 中的代码不执行的问题,原来在子组件中写这个方法会不执行,解决方式可以参考 https://stackoverflow.com/questions/42045433/vue-router-beforerouteleave-doesnt-stop-subcomponents

v-model vs :value and on-change

近期再使用组件的时候有这样一个场景:根据 state 中的值给组件赋值,同时期望用户手动使用该组件的时候触发事件。由此引出这个问题:

v-model 原理

官方文档中给出了自定义 v-model 的示例(https://cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model)由此也可以推断出 v-model 的本质:(双向数据绑定的原理此处不再赘述)

<input v-model="test"> 
<!--本质上就是如下语句:-->

<input :value="test" @input="test = $event.target.value">
  • 方法 1:然而针对上面我们提到的场景,我们更希望在 @input 中做一些其他的处理,因此此处也就是这种场景下更适合使用 :value+on-change 的组合
  • 方法 2:使用 v-model 和 state 结合 vuex中获取的数据使用 v-model 绑定

props vs v-model

场景:子组件 a 中含有一个表单,父组件 A 希望通过 props 将初始值传给子组件 a, 但显然表单的 v-model 不能和 props 绑定,否则将会遇到这种报错

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value.

首先撇开上面场景不谈,子组件中有表单的情况最佳是直接将 a 中的 data 中的值与 v-model 绑定,那其实再结合上面的提示,我们可以直接在声明 data 时将 props 传给 data: 如官方文档: https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

vue-cli

详细配置可以参考

而其中关于 configureWebpackchainWebpack 的区别,前者用对象或者函数的方式去修改 webpack 配置,后者是通过链式操作的方式

注意:英文版文档更全面(这意味着中文版缺失了部分选项

why app.js is so big

最近将前端项目部署在开发机上并以开发模式启动后,在办公网下访问结果发现异常慢,打开控制台发现app.js体积有 20M+ 其实本质是因为 development模式下启动时没有任何的 optimization

Vue Cli 3 Bundle Size is too large ! ( app.js is now 8 MB)

vue-cli 模式和变量🌟🌟🌟🌟🌟

Quick guide to webpack bundle and code splitting with React🌟🌟🌟🌟

目前很多 Vue 项目都是使用 vue-cli 直接搭建,默认情况下NODE_ENV=development 创建一个 webpack 配置,该配置启用热更新,不会对资源进行 hash 也不会打出 vendor bundles,同时包含 webpack 的 HMR client ,这样 app.js 就异常大,目的是为了在开发的时候能够快速重新构建。

注释:vender bundles 包含了项目依赖的所有框架和库。通过将所有这些代码构建到一个 bundle 中,客户端可以有效地缓存捆绑包,并且您只需要在框架或库更新时重建捆绑包。

html 标签的 target 属性

标签 target 属性

应怎样看待 target="_blank" 的使用?

  • 使用 rel="noopener" 预防target="_blank"漏洞

vue.set 使用

reference:

Vue.set()和this.$set()介绍

Vue 细节与最佳实践

vue中遇到的坑 — 变化检测问题(数组相关)

结论: 如果想更新已经在 data 中定义的数组或对象中添加新字段需要使用this.$set来达到视图的更新。

export default {
    data(){
        return {
                items:{
                    a:1,
                }
        }
    }
}
// this.items.a=2; 此时是响应式的
// this.items.b=2; 此时不是响应式的
  • 原因:由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除因为Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。
  • 因此此时应该用 set 方法为其新增一个响应式的属性:Vue.set( target, propertyName/index, value )

media Query

最近在工作中遇到了一些需要适配不同设备的开发,特此记录一下不同设备的区分

Media Queries: How to target desktop, tablet, and mobile?

vue 行内样式设置 hover

最近工作中有这样一个场景「利用v-for渲染了div,同时每个div的颜色是通过数据来改变的,即:设置为了行内样式,行内样式优先级最高,此时用 less 或 css 设置 hover 的 background-color 就会失去意义」

related work

React中的内联CSS样式:如何实现:hover?

  1. 通过组件内定义一个状态,监听 mouseover mouseout 事件对其进行改变,相应的
    更新内联样式
    • 与之类似的就是监听 mouseover mouseout 事件动态添加 div 的 class 名称。不过这种方式仍然无法解决问题,仍然因为行内样式具有最高优先级

resolved

变通思路,通过数据变化来更新 div 的 class 名,在 css 中定义样式,此时再写 hover 的相关样式就不会有被高优覆盖的情况了。

vue css scoped module

Scoped CSS

CSS Modules

Vue:scoped与module的使用与利弊

除了官方文档中有提到 scoped 会有性能上的影响外,在大型项目中使用 module 有利于快速定位。

什么是 postCSS?

vuex使用

  • mapState mapGetters 一般放在组件的computed属性中
  • mapMutations mapActions 一般放在组件的methods属性中

vuex mutation change state

我们已经知道不能直接修改 state,只能通过 mutation 修改。对于 object 类型的 state,我们在文档中也看到可以使用 Vue.set 或者对象解构替换的方式进行,当然采用如下这种利用浅拷贝特性的方式也可行。(如果不可行需要自行 check 一下对象传递过程中的其他问题)

  state: {
    test: {
      a: 1,
      b: 2,
    }
  },
  
  mutations: {
      CHANGE_TEST(_state, payload) {
        _state.test = {
            ..._state,
            a: 2,
        }
      },
      CHANGE_TEST(_state, payload) {
          let tmp = _state.test
          tmp.a = 2  // it will change state.test.a
      }
  }

loading 加载时机与 vuex dispatch action

这里也在「FE 每周问题总结」中进行过同下整理

为什么将 loading 加载时机这种与业务强相关的内容和 vuex 联系起来呢,且看下面的分解

Composing Actions

Promise.prototype.finally()

使用 loading 我们可以解决在 vuex 中设置了初始值 state,但通过 dispatch action 更新 state 这期间造成的“页面闪烁”问题。那么我们到底具体什么位置写 loading 呢?

  • 最好是 store 中,将 loading 作为 state 的一个变量,在 action 中通过 mutation 修改
  • 其次是在组件内部(适用于除了处理 loading 还要处理组件内部一些其他非公用 store 逻辑的场景),使用 mapActions 本质还是使用 store.dispatch,而 dispatch 本质就是 promise,我们可以在 promise.finally() 中处理 loading 逻辑

动态组件 component

component

渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。
更多的可以参考我在github上的项目:vue_prac

混入

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

混入

created和mounted生命周期函数的区别

vue中created钩子函数与mounted钩子函数的使用区别

created

在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer), 属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

=====>
模板还没有被渲染成 html,也就是这时候通过 id 什么的去查找页面元素是找不到的

那么随之而来有一个问题,到底 props 先被注入到实例中还是 data 呢,当然前文props vs v-model中我提到了直接在 data 中使用 props 的案例,则答案不言而喻了.

执行顺序 beforeCreate inject -> Props -> Methods -> Data -> Computed -> Watch ->provide-> created

vue组件初始化的执行顺序详解

mounted

el 被新创建的 vm. e l 替 换 , 并 挂 载 到 实 例 上 去 之 后 调 用 该 钩 子 。 如 果 r o o t 实 例 挂 载 了 一 个 文 档 内 元 素 , 当 m o u n t e d 被 调 用 时 v m . el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm. elrootmountedvm.el 也在文档内。

=====>
mounted钩子函数一般是用来向后端发起请求拿到数据以后做一些业务处理。这时候vue模板已经渲染完毕。因此,Dom操作一般是在mounted钩子函数中进行的

computed 计算属性

通常来讲计算属性会在初级面试中和methods进行对比,计算属性更加的"智能",它总是根据它依赖的值的变化而变化,因此也基于这个原因,为了避免出现死循环,通常不建议在computed计算属性中修改data中的值

template标签的使用

官方的解释中:

一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。

也就是说个人觉得可以认为是在标签里面又插进来一个模版。

可以首先参考这篇文章:

关于template标签用法总结(含vue中的用法总结)

Vue中的template标签的使用和在template标签上使用v-for

vuex使用

关于vuex的讨论已经是老生常谈了,但因为好久不用未免生疏,个人觉得理解起来一定要从原理入手

image

state===>获取状态

mapState不同用法

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}
// 当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])
// 而下面这段代码的意思是:b:state=>state.a.b
...mapState('a', ['b']),

getter===>类似于computed计算属性 依赖于state的变化

mutation===>
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。

// mutations必须是同步函数
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
// 你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

action===>
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。

vuex vs eventBus

我们知道 Vue 中的全局状态管理有 vuex 以及 eventBus,正如 Vue 核心开发者所言,通常我们会选择 vuex 而避免使用 eventBus,那么具体是什么原因呢,我们到底在什么场景下使用 eventBus 更好呢?

Get on the Event Bus: Vue.js

Clarification on not using global event bus

Vue.js: why event bus is bad idea

使用 eventBus 有如下的一些缺点:

  • 事件名的维护成本
  • 无法知道哪个组件正在发送事件,同时任何人都可发送事件
  • 在组件中发送事件必须确保该组件 dom 存在,才能监听事件消息,这会让逻辑变复杂

相对于以上,vuex 有命名空间等更具有在状态管理方面的优势,当然 eventBus 也有一些可以使用它的场景,比如在处理全局的长连接错误上即可以全局的分发。

vue清理console

references:

vue-cli – build时自动清除console

babel-plugin-transform-remove-console

vue-cli4 有所改动参考 https://cli.vuejs.org/migrating-from-v3/#vue-cli-service,同时应该注意自己vue.config.js配置中 lintOnSave的设定

vuex 修改数据

tips:

  1. 当 state 中某个变量时对象数组时,如果在 mutation 中直接更新数组中的某个元素则不会引起数据的变化如
state: {
    test: [{
        name: 'jerry',
        age:12,
    }]
}
// 此时直接更新 `test[1]` 为某个对象,Vue 监测不到数据变化正确的方式是直接更新 `test[1].name`

vue3

vue3 composition API vs vue2 options API

Vue 3 Composition API vs. Options API

options API:

like data, methods, and mounted and others in Options API

composition API

vue3 的核心,使用 setup 函数,根据逻辑相关性组织代码,提高可读性和可维护性。

options API 以业务相关性组织代码随着项目的逐渐变大会逐渐臃肿不易维护,而 vue3 的 composition API 以逻辑相关性组织代码,则弥补了它的缺点:

  • 可组合代码共享(私以为这是最大的优点)

Vue-i18n

注意可以结合 localStorage 使用,同时在更换语言时向 html 添加 lang 以用以样式替换:

const html = document.querySelector('html');
      html && html.setAttribute('lang', locale);

此时则可以使用

// container 中的文字在英文模式下为红色
.container:lang(en){
    color: red;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值