Vue 3 已经稳定了相当长一段时间了。许多代码库都在生产环境中使用它,其他人最终都将不得不迁移到 Vue 3。我现在有机会使用它并记录了我的错误,下面这些错误你可能想要避免。
使用 Reactive 声明原始值
数据声明在过去都是非常直接的,但是现在有很多帮助函数供我们使用。目前的规则是:
- 使用
reactive
声明Object, Array, Map, Set
- 使用
ref
声明String, Number, Boolean
Vue 3 已经稳定了相当长一段时间了。许多代码库都在生产环境中使用它,其他人最终都将不得不迁移到 Vue 3。我现在有机会使用它并记录了我的错误,下面这些错误你可能想要避免。
数据声明在过去都是非常直接的,但是现在有很多帮助函数供我们使用。目前的规则是:
reactive
声明Object, Array, Map, Set
ref
声明String, Number, Boolean
市面上常用的命名规范:
camelCase
(小驼峰式命名法 —— 首字母小写)PascalCase
(大驼峰式命名法 —— 首字母大写)kebab-case
(短横线连接式)Snake
(下划线连接式)全部采用小写方式, 以短横线分隔。例:my-project-name
。
相信用过 vue 的小伙伴,肯定被面试官问过这样一个问题:在 vue 中动态的引入图片为什么要使用 require?
有些小伙伴,可能会轻蔑一笑:呵,就这,因为动态添加 src 被当做静态资源处理了,没有进行编译,所以要加上 require, 我倒着都能背出来......
emmm... 乍一看好像说的很有道理啊,但是仔细一看,这句话说的到底是个啥?针对上面的回答,我不禁有如下几个疑问:
设计模式是一套被反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。它是为了可重用代码,让代码更容易的被他人理解并保证代码的可靠性。
设计模式实际上是“拿来主义”在软件领域的贯彻实践,它是一套现成的工具,拿来即用。下面来看一下设计模式的设计原则。
单一职责原则、开放封闭原则、里式替换原则、接口隔离原则 、依赖反转原则 、最少知识原则。
下面我们一起来看看几种在前端领域常见的设计模式:
单例模式、工厂模式、策略模式、代理模式、适配器模式、观察者模式/发布-订阅模式
项目开发中,一般都会有开发环境、测试环境、生产环境等多个环境,所以项目在打包时我们就会调用不同环境的接口,此时我们就要通过配置变量来解决这一问题。
下面以开发、测试、生产这 3 个环境为例。
.env.development
.env.test
.env.production
history
模式会出现刷新页面后,页面出现 404。解决的办法是用nginx
配置一下。
在nginx
的配置文件中修改
location /{
root /data/nginx/html;
index index.html index.htm;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
break;
}
}
SPA(single-page application)仅在 Web 页面初始化时加载相应的 HTML、CSS、JavaScript。一旦页面加载完成,SPA 不会因为用户的操作二进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户交互,避免页面的重新加载。
优点:
nextTick
支持两种形式使用方式:
Promise
,还支持 Promise.then
的形式。let pending = false,
timeFunc,
callbacks=[];
//cb:执行的回调函数,context:执行上下文参数
function nextTick(cb,context){
let _resolve=null;
callbacks.push(()=>{
if(cb){
try{
cb.call(context)
}catch(e){
handleError(e,ctx,'nextTick)
}
}else if(_resolve){
_resolve(context)
}
})
if(!pending){
pending=true;
timeFunc()
}
if(!cb&&typeof Promise !== "undefind"){
rteurn new Promise(resolve=>_resolve=resolve)
}
}
let isUsingMicroTask = false;
if (typeof Promise !== 'undefined' && isNative(Promise)) {
//判断1:是否原生支持Promise
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
//判断2:是否原生支持MutationObserver
let counter = 1
const observer = new MutationObserver(flushCallbacks)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
//判断3:是否原生支持setImmediate
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
//判断4:上面都不行,直接用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
nextTick(()=>{
console.log("nextTick callback")
})
nextTick().then(()=>{
console.log("nextTick Promise")
})
自从引入组合式 API 的概念以来,一个主要的未解决的问题就是 ref
和 reactive
到底用哪个。reactive
存在解构丢失响应性的问题,而 ref
需要到处使用 .value
则感觉很繁琐,并且在没有类型系统的帮助时很容易漏掉 .value
。
例如,下面的计数器:
<template>
<button @click="increment">{{ count }}</button>
</template>