来吧,解锁 vue3 全家桶+Ts 的正确姿势,2024移动开发者真的太难了

41 阅读4分钟

最后

在面试前我花了三个月时间刷了很多大厂面试题,最近做了一个整理并分类,主要内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

  • HTML5新特性,语义化

  • 浏览器的标准模式和怪异模式

  • xhtml和html的区别

  • 使用data-的好处

  • meta标签

  • canvas

  • HTML废弃的标签

  • IE6 bug,和一些定位写法

  • css js放置位置和原因

  • 什么是渐进式渲染

  • html模板语言

  • meta viewport原理

开源分享:docs.qq.com/doc/DSmRnRG…

vuex


使用this.$store

import { createStore } from 'vuex';

export type State = {

count: number

}

export default createStore({

state: {

count: 0

}

});

需要创建一个声明文件vuex.d.ts

// vuex.d.ts

import {ComponentCustomProperties} from 'vue';

import {Store} from 'vuex';

import {State} from './store'

declare module '@vue/runtime-core' {

interface ComponentCustomProperties {

$store: Store

}

}

在setup中使用

定义InjecktionKey

在安装插件时传入key

在使用useStore时传入

import { InjectionKey } from 'vue';

import { createStore, Store } from 'vuex';

export type State = {

count: number

}

// 创建一个injectionKey

export const key: InjectionKey<Store> = Symbol('key');

// main.ts

import store, { key } from './store';

app.use(store, key);

<script lang="ts">

import { useStore } from 'vuex';

import { key } from '@/store';

export default defineComponent({

setup () {

const store = useStore(key);

const count = computed(() => store.state.count);

return {

count

}

}

})

模块

新增一个todo模块。导入的模块,需要是一个vuex中的interface Module的对象,接收两个泛型约束,第一个是该模块类型,第二个是根模块类型

// modules/todo.ts

import { Module } from 'vuex';

import { State } from '../index.ts';

type Todo = {

id: number,

name: string,

completed: boolean

}

const initialState = {

todos: [] as Todo[]

};

export type TodoState = typeof initialState;

export default {

namespaced: true,

state: initialState,

mutations: {

addTodo (state, payload: Todo) {

state.todos.push(payload);

}

}

} as Module<TodoState, State>; //Module<S, R> S 该模块类型 R根模块类型

// index.ts

export type State = {

count: number,

todo?: TodoState // 这里必须是可选,不然state会报错

}

export default createStore({

state: {

count: 0

}

modules: {

todo

}

});

使用:

setup () {

console.log(store.state.todo?.todos);

}

elementPlus


yarn add element-plus

完整引入

import { createApp } from 'vue'

import ElementPlus from 'element-plus';import 'element-plus/lib/theme-chalk/index.css';import App from './App.vue';

import 'dayjs/locale/zh-cn'

import locale from 'element-plus/lib/locale/lang/zh-cn'

const app = createApp(App)

app.use(ElementPlus, { size: 'small', zIndex: 3000, locale })

app.mount('#app')

按需加载

需要安装babel-plugin-component插件:

yarn add babel-plugin-component -D

// babel.config.js

plugins: [

[收起

'component',

{

libraryName: 'element-plus',

styleLibraryName: 'theme-chalk'

}

]

]

import 'element-plus/lib/theme-chalk/index.css';

import 'dayjs/locale/zh-cn';

import locale from 'element-plus/lib/locale';

import lang from 'element-plus/lib/locale/lang/zh-cn';

import {

ElAside,

ElButton,

ElButtonGroup,

} from 'element-plus';

const components: any[] = [

ElAside,

ElButton,

ElButtonGroup,

];

const plugins:any[] = [

ElLoading,

ElMessage,

ElMessageBox,

ElNotification

];

const element = (app: any):any => {

// 国际化

locale.use(lang);

// 全局配置

app.config.globalProperties.$ELEMENT = { size: 'small' };

components.forEach(component => {

app.component(component.name, component);

});

plugins.forEach(plugin => {

app.use(plugin);

});

};

export default element;

// main.ts

import element from './plugin/elemment'

const app = createApp(App);

element(app);

axios


axios的安装使用和vue2上没有什么大的区别,如果需要做一些扩展属性,还是需要声明一个新的类型。

type Config = AxiosRequestConfig & {successNotice? : boolean, errorNotice? : boolean}

import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';

import { ElMessage } from 'element-plus';

const instance = axios.create({

baseURL: process.env.VUE_APP_API_BASE_URL || '',

timeout: 120 * 1000,

withCredentials: true

});

// 错误处理

const err = (error) => {

if (error.message.includes('timeout')) {

ElMessage({

message: '请求超时,请刷新网页重试',

type: 'error'

});

}

if (error.response) {

const data = error.response.data;

if (error.response.status === 403) {

ElMessage({

message: 'Forbidden',

type: 'error'

});

}

if (error.response.status === 401) {

ElMessage({

message: 'Unauthorized',

type: 'error'

});

}

}

return Promise.reject(error);

};

type Config = AxiosRequestConfig & {successNotice? : boolean, errorNotice? : boolean}

// 请求拦截

instance.interceptors.request.use((config: Config) => {

config.headers['Access-Token'] = localStorage.getItem('token') || '';

return config;

}, err);

// 响应拦截

instance.interceptors.response.use((response: AxiosResponse) => {

const config: Config = response.config;

const code = Number(response.data.status);

if (code === 200) {

if (config && config.successNotice) {

ElMessage({

message: response.data.msg,

type: 'success'

});

}

return response.data;

} else {

let errCode = [402, 403];

if (errCode.includes(response.data.code)) {

ElMessage({

message: response.data.msg,

type: 'warning'

});

}

}

}, err);

export default instance;

setup script


官方提供了一个实验性的写法,直接在script里面写setup的内容,即:setup script

之前我们写组件是这样的:

<script lang="ts">

import { ref, defineComponent } from "vue";

import ImgReview from "./components/ImgReview.vue";

export default defineComponent({

components: {

ImgReview,

},

setup() {

const count = ref(0);

return { count };

}

});

启用setup script后:在script上加上setup

<script lang="ts" setup>

import { ref } from "vue";

import ImgReview from "./components/ImgReview.vue";

const count = ref(0);

是不是看起来简洁了很多,组件直接导入就行了,不用注册组件,数据定义了就可以用。其实我们可以简单的理解为script包括的内容就是setup中的,并做了return

导出方法

<script lang="ts" setup>

const handleClick = (type: string) => {

console.log(type);

}

定义props

使用props需要用到defineProps来定义,具体用法跟之前的props写法类似:

基础用法

<script lang="ts" setup>

import { defineProps } from "vue";

const props = defineProps(['userInfo', 'gameId']);

构造函数进行检查 给props定义类型:

const props = defineProps({

gameId: Number,

userInfo: {

type: Object,

required: true

}

});

使用类型注解进行检查

defineProps<{

name: string

phoneNumber: number

userInfo: object

tags: string[]

}>()

可以先定义好类型:

interface UserInfo {

id: number,

name: string,

age: number

}

defineProps<{

name: string

userInfo: UserInfo

}>()

defineEmit

<script lang="ts" setup>

import { defineEmit } from 'vue';

// expects emits options

const emit = defineEmit(['kk', 'up']);

const handleClick = () => {

emit('kk', '点了我');

};

<Comp @kk="handleClick"/>

<script lang="ts" setup>

const handleClick = (data) => {

console.log(data)

}

获取上下文

在标准组件写法里,setup 函数默认支持两个入参:

| 参数 | 类型 | 含义 |

| --- | --- | --- |

| props | object | 由父组件传递下来的数据 |

| context | object | 组件的执行上下文 |

在setup script 中使用useContext获取上下文:

<script lang="ts" setup>

import { useContext } from 'vue'

const { slots, attrs } = useContext();

获取到的slots,attrssetup里面的是一样的。

作者:FinGet

最后

好了,这就是整理的前端从入门到放弃的学习笔记,还有很多没有整理到,我也算是边学边去整理,后续还会慢慢完善,这些相信够你学一阵子了。

做程序员,做前端工程师,真的是一个学习就会有回报的职业,不看出身高低,不看学历强弱,只要你的技术达到应有的水准,就能够得到对应的回报。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

学习从来没有一蹴而就,都是持之以恒的,正所谓活到老学到老,真正懂得学习的人,才不会被这个时代的洪流所淘汰。