目录
4、使用vue3 + vite + TypeScript 搭建新项目
3、遇到的坑:vue中给点击事件@click 使用三元运算符
2. uni.redirectTo(object) 关闭当前页面,跳转到应用中其他页面(同router.replace)
3. uni.switchTab(object) 跳转到tabBar页面,关闭其他所有非tabBar页面
5. uni.reLaunch(object) 关闭所有页面,打开到应用内的某个页面
1. uni.showToast(object) 和 uni.hideToast()
2. uni.showLoading(object) 和 uni.hideLoading()
4. uni.showActionSheet(object)
1、uni-app view相当于div,text相当于span,image=img
2. 原生js写法:window.location.reload()
4、uni-app easycom组件模式:无需引入、注册组件,直接使用
1、遇到的坑:uni-app 跳转路径时前面自动拼接pages/xxx/,导致路由跳转失败
2、uni-app vue2的uni.request(object)封装
3、遇到的坑:vue3无法使用splice删除数组中某个对象
3、vue3 对银行卡号位数进行格式化(每隔4位自动补一个空格)
4、input 输入金额格式化,只能输入一个小数点,只能输入两位小数
5、遇到的坑:ts 联合类型->类型“xxx”的参数不能赋给类型“string”的参数
6、ts console报错:类型“any”的参数不能赋给类型“never”的参数
1、vant组件库中的List列表:瀑布流滚动加载,用于展示长列表
2、遇到的坑:try...catch...机制,后端传来的错误信息只在catch里获取
1、遇到的坑:vant组件库中的轮播图、tab标签页显示第二张图片后面会有第三张图片的边边
2、遇到的坑:在catch到错误之后,路由一直跳转不了失败结果提示页
3、padding 三位数表示什么?第二位表示左右的padding
1、在vue3、ts中使用three.js展示3D(glb)模型
1、vue3、ts使用three.js加载glb模型(加载完成就显示模型)
2、vue3、ts使用three.js加载glb模型(模型显示不出来的问题)
2. 实在不行,就加上 requestAnimationFrame()
2022.09.01
1、overflow:auto;
如果内容被修剪,则浏览器会显示滚动条,以便查看其余内容。
2、封装通用axios返回值类型
在src目录下新建axios.d.ts文件
import axios from 'axios'
declare module 'axios' {
interface AxiosInstance {
(data: AxiosRequestConfig): Promise<{
code: number
data: any
message: string
}>
}
}
3、vite构建的vue3项目适配移动端
安装
npm i lib-flexible postcss-pxtorem -D
配置vite.config.ts,在此文件中添加以下代码
import postCssPxToRem from "postcss-pxtorem"
在vite.config.ts中找到css部分,添加以下代码
css:{
// 此代码为适配移动端px2rem
postcss: {
plugins: [
postCssPxToRem({
rootValue: 37.5, // 1rem的大小
propList: ['*'], // 需要转换的属性,这里选择全部都进行转换
})
]
}
}
找到main.ts加入以下代码
import 'lib-flexible'
在index.html中加入以下meta
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
4、使用vue3 + vite + TypeScript 搭建新项目
1. 新建项目
npm init vite project(项目名称)
选择vue-ts
进入
cd project(项目路径)
安装依赖
npm install
启动
npm run dev
2. 配置vue-router 4
安装vuex
npm install vue-router@4.0.12
配置vue-router
在项目src下新建router目录,然后添加index.ts文件
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
const routes: Array<RouteRecordRaw> = [
// {
// name: 'Home',
// path: '/home',
// component: () => import('../views/home/index.vue')
// }
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
将router引入到main.ts中
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
3. 配置vuex 4
安装vuex
npm install vuex@4
配置vuex
在项目src下新建store目录,然后添加index.ts文件
import { createStore } from 'vuex'
import modules from './modules'
export const store = createStore({
modules
})
在store目录下,添加modules文件夹,在modules文件夹下新建index.ts文件以及其他模块文件
index.ts文件
import base from './base'
import home from './home'
import order from './order'
import my from './my'
export default {
base,
home,
order,
my
}
其他模块文件
export default {
namespaced: true,
state: {},
mutations: {},
actions: {},
getters: {}
}
5、 深拷贝和浅拷贝
1. 浅拷贝
第一种方法:object.assign()
let obj1 = Object.assign({}, obj);
第二种方法:使用扩展运算符(...)
let obj1 = {...obj};
第三种方法:Array.prototype.concat()
let arr1 = arr.concat([]);
第四种方法:Array.prototype.slice()
let arr1 = arr.slice();
2. 深拷贝
第一种方法:序列化和反序列化
let obj1 = JSON.parse(JSON.stringify(obj))
第二种方法:引入lodash工具库
第三种方法:手写递归实现深拷贝(兼容对象和数组)
const deepClone = target => {
if(typeof target === 'object') {
const cloneTarget = Array.isArray(target) ? [] : {};
for (const key in target) {
cloneTarget[key] = deepClone(target[key]);
};
return cloneTarget;
} else {
return target;
}
}
第四种方法:jQuery.extend()方法,需引入jQuery库
let obj1 = jQuery.extend(true, {}, obj); //第一个参数为true才是深拷贝
2022.09.02
1、同步与异步
同步:一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去,这样就称为同步,同步代码会按照一定的顺序去执行。
异步:进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。
实现异步的方法:定时器。
解决异步:通过回调的方式去调用函数,来控制函数执行的先后顺序。
回调函数嵌套过多,容易造成回调地狱。使用Promise方法避免了回调地狱。
//Promise语法
let myPromise = new Promise(function(resolve, reject) {
resolve(); // 成功时
reject(); // 出错时
});
myPromise.then(
function(value) { /* 成功时的代码 */ },
function(error) { /* 出错时的代码 */ }
);
2、事件循环 event loop
console.log('start');
setTimeout(function(){
console.log('setTimeout');
},0)
new Promise(resolve =>{
console.log('Promise');
resolve();
})
.then(function(){
console.log('promise1');
})
.then(function(){
console.log('promise2');
})
console.log('end');
结果: start -> Promise -> end -> promise1 -> promise2 -> setTimeout
执行栈:一个用来存放函数的执行上下文环境的一个栈结构,遵循着先进后出的规则。
宏任务:每次执行栈执行的代码就是一个宏任务。
宏任务队列包括:script、setTimeout、setInterval、setImmediate (node环境下是,而浏览器环境下不是)、I/O、UI-rendering、requestAnimationFrame (在浏览器环境是,而node环境不是)。
微任务:当前 task 执行结束后立即执行的任务。
微任务队列包括:process.nextTick、promise.then、MutationObserver。
事件循环:等待宿主环境分配宏观任务,反复等待 - 执行即为Event-Loop(事件循环)。
事件循环的执行顺序:
第一步:找出同步代码,优先执行,这属于宏任务。
第二步:当执行完所有的同步代码后,执行栈为空,检查是否有异步代码要执行。(注意只是检查,并非此刻检查出来就执行,而是看它是第几层次的异步代码在第几次循环执行,引擎在找到异步代码的时候会将其挂起,即装起来放在一边)
第三步:执行微任务。
第四步:执行完微任务后,有必要的情况下会渲染页面。
第五步:开启下一轮Event-Loop,执行宏任务中的代码。(这就算是下次事件循环的开始第一步,上一次的异步,在此刻也将变为这一次执行的同步)
第一步找出同步代码:
console.log('start');
new Promise(resolve =>{
console.log('Promise');
resolve();
})
console.log('end');
将其执行完;于是优先打印出了start -> Promise -> end
第二步就在执行完所有同步代码后,检查是否有异步代码,
我们很快就能找到定时器所在异步代码(即便定时器定时为0,那也是属于异步代码)
setTimeout(function(){
console.log('setTimeout');
},0)
将其挂起,放到一边先不要管。
第三步则是找到微任务并将其执行:
.then(function(){
console.log('promise1');
})
.then(function(){
console.log('promise2');
})
那么继上一次打印结果之后再次打印出了:promise1 -> promise2
第四步,执行完微任务后,有必要将会渲染页面,但是这里我们是纯原生JS,
并没有需要渲染的DOM结构,可以跳过这个环节,同时,这一轮Event-Loop结束。
第五步,开启下一轮Event-Loop,我们刚才挂起的异步代码已然成为了这一轮的第一个步骤中的同步代码
那么它将会成为这一轮Event-Loop的第一步首先执行。
setTimeout(function(){
console.log('setTimeout');
},0)
那么我们将会继续打印出setTimeout
本来我们在执行完这个操作应该继续循环Event-Loop操作,但是我们知道所有代码都已经执行完,
后续也没有可执行代码,也就不用执行下去了。
转载于:十分钟带你了解javascript里的面试“常客”——Event-Loop,async-await - 掘金 (juejin.cn)
3、遇到的坑:vue中给点击事件@click 使用三元运算符
错误写法:
@click="!userInfo.account ? createAccount : ''"
正确写法:
@click="!userInfo.account ? createAccount() : ''"
要给事件加上()括号。
4、将用户信息通过vuex存入localStorage中
只要一请求actions中的函数接口,就会把获取到的数据随时存入localStorage中。
import { ActionContext } from 'vuex'
// IStore为每个vuex模块的总数据type
import { IStore } from '../types'
export type IUser = {
userInfo: IUserInfo
}
export interface IUserInfo {
token: string
id: string
name: string
mobile: string
avatar: string
}
// 先定义空数据
const userInfo = {
token: '',
id: '',
name: '',
mobile: '',
avatar: ''
}
// 定义一个user,从本地获取数据 或者 赋值userInfo的空数据
const user = JSON.parse(localStorage.getItem('userInfo') || JSON.stringify(userInfo))
export default {
namespaced: true,
state: {
userInfo: user
},
mutations: {
['SET_USER_INFO'](state: IUser, payload: IUserInfo) {
state.userInfo = { ...state.userInfo, ...payload }
// 将数据 或者 空对象存入localStorage中
localStorage.setItem('userInfo', JSON.stringify(state.userInfo || {}))
}
},
actions: {
async getUserInfo({ commit }: ActionContext<IUser, IStore>, payload: {}) {
const res = await getUserInfoApi()
if (res.code === 200) {
// 触发mutations中的函数
commit('SET_USER_INFO', res.data || {})
}
}
}
}
5、项目中凌乱的各种TS类型注解
使用tree-node-cli生成树状目录
treee -L 4 -I "node_modules|.idea|objects|.git" -a --dirs-first

以order为例进行理解。
store/types/order.ts文件
// 全部状态的订单数据
export interface IMyOrder {
// 状态:pending 待发货,shipped 已发货,received 已收货,completed 已完成,canceled 已取消
[pending: string]: IMyOrderData
shipped: IMyOrderData
received: IMyOrderData
completed: IMyOrderData
canceled: IMyOrderData
}
// 订单数据,查到共有多少条
export interface IMyOrderData {
total: number
list: IMyOrderList[]
}
// 订单里详细的数据字段
export interface IMyOrderList {
id: string
buyer_name: string
price: string
......
}
store/modules/order.ts文件
import { IMyOrder, IMyOrderData, IMyOrderList } from '../types/order'
// IOrderState对象里的属性都与state里的一致
// 定义state的type:IOrderState
export type IOrderState = {
myOrder: IMyOrder // 全部的订单数据
orderDetail: IMyOrderList // 订单里详细的数据字段
ActiveTab: number
}
state: {
myOrder: {},
orderDetail: {},
ActiveTab: 0
},
// mutations
// state 的类型注解为 state的type
// payload 的类型注解为 actions中传的数据类型(定义接口Interface)
['SET_ORDER_DETAIL'](state: IOrderState, payload: IMyOrderList) {
state.orderDetail = payload
},
// actions
// {commit} 的类型注解为 ActionContext<state的type, vuex总的type>
// payload 的类型注解为 传给后端的数据类型
async myOrderDetail({ commit }: ActionContext<IOrderState, IStore>, payload: string) {
const res = await myOrderDetailApi(payload)
commit('SET_ORDER_DETAIL', res.data || {})
},
api/order.ts文件
// 要求以什么参数查询订单
export interface IMyOrderApi {
limit: number // 查询数量
skip: number // 开始索引
sort: number // -1倒叙,1正序
state?: string
sortBy: string // 按什么分类查
}
// 订单接口
// data 的类型注解为 传给后端的数据类型(定义接口Interface)
export const myOrderApi = (data: IMyOrderApi) => {
return service({
url: '/me/order',
method: 'POST',
data // 传给后端的数据
})
}
store/types.ts文件
// 引入所有vuex模块的state的type
import { IOrderState } from './modules/order'
......
export interface IStore {
order: IOrderState
......
}

本文是2022年9月的前端学习笔记,涵盖了前端开发中的常见问题与技巧,包括overflow:auto;的使用、axios返回值类型封装、uni-app移动端适配、vue3项目搭建、深拷贝与浅拷贝的区别、uni-app路由跳转API、uni-app交互反馈API、CSS布局与动画、uni-app页面滚动穿透、vue3与ts的深入实践等。此外,还讨论了在使用vant组件库、uni-app和three.js时遇到的问题与解决方案。
最低0.47元/天 解锁文章
1157

被折叠的 条评论
为什么被折叠?



