解锁vue3全家桶和ts正确姿势
ztj100 2025-01-05 01:03 11 浏览 0 评论
基础语法
定义data
- script标签上lang="ts"
- 定义一个类型type或者接口interface来约束data
- 可以使用ref或者toRefs来定义响应式数据
- 使用ref在setup读取的时候需要获取xxx.value,但在template中不需要
- 使用reactive时,可以用toRefs解构导出,在template就可以直接使用了
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from 'vue';
type Todo = {
id: number,
name: string,
completed: boolean
}
export default defineComponent({
const data = reactive({
todoList: [] as Todo[]
})
const count = ref(0);
console.log(count.value)
return {
...toRefs(data)
}
})
</script>
复制代码
定义props
props需要使用PropType泛型来约束。
<script lang="ts">
import { defineComponent, PropType} from 'vue';
interface UserInfo = {
id: number,
name: string,
age: number
}
export default defineComponent({
props: {
userInfo: {
type: Object as PropType<UserInfo>, // 泛型类型
required: true
}
},
})
</script>
复制代码
定义methods
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from 'vue';
type Todo = {
id: number,
name: string,
completed: boolean
}
export default defineComponent({
const data = reactive({
todoList: [] as Todo[]
})
// 约束输入和输出类型
const newTodo = (name: string):Todo => {
return {
id: this.items.length + 1,
name,
completed: false
};
}
const addTodo = (todo: Todo): void => {
data.todoList.push(todo)
}
return {
...toRefs(data),
newTodo,
addTodo
}
})
</script>
复制代码
vue-router
- createRouter创建router实例
- router的模式分为:
- createWebHistory -- history模式
- createWebHashHistory -- hash模式
- routes的约束类型是RouteRecordRaw
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Home from '../views/Home.vue';
const routes: Array< RouteRecordRaw > = [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
复制代码
扩展路由额外属性
在实际项目开发中,常常会遇到这么一个场景,某一个路由是不需要渲染到侧边栏导航上的,此时我们可以给该路由添加一个hidden属性来实现。
在ts的强类型约束下,添加额外属性就会报错,那么我们就需要扩展RouteRecordRaw类型。
// 联合类型
type RouteConfig = RouteRecordRaw & {hidden?: boolean}; //hidden 是可选属性
const routes: Array<RouteConfig> = [
{
path: '/',
name: 'Home',
component: Home,
hidden: true,
meta: {
permission: true,
icon: ''
}
}
];
复制代码
在setup中使用
需要导入useRouter创建一个router实例。
<script lang="ts">
import { useRouter } from 'vue-router';
import { defineComponent } from 'vue';
export default defineComponent({
setup () {
const router = useRouter();
goRoute(path) {
router.push({path})
}
}
})
</script>
复制代码
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<State>
}
}
复制代码
在setup中使用
- 定义InjecktionKey
- 在安装插件时传入key
- 在使用useStore时传入
import { InjectionKey } from 'vue';
import { createStore, Store } from 'vuex';
export type State = {
count: number
}
// 创建一个injectionKey
export const key: InjectionKey<Store<State>> = 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
}
}
})
</script>
复制代码
模块
新增一个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。
之前我们写组件是这样的:
<template>
<div>
{{count}}
<ImgReview></ImgReview >
</div>
</template>
<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 };
}
});
</script>
复制代码
启用setup script后:在script上加上setup
<template>
<div>
{{count}}
<ImgReview></ImgReview>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import ImgReview from "./components/ImgReview.vue";
const count = ref(0);
</script>
复制代码
是不是看起来简洁了很多,组件直接导入就行了,不用注册组件,数据定义了就可以用。其实我们可以简单的理解为script包括的内容就是setup中的,并做了return。
导出方法
<script lang="ts" setup>
const handleClick = (type: string) => {
console.log(type);
}
</script>
复制代码
定义props
使用props需要用到defineProps来定义,具体用法跟之前的props写法类似:
基础用法
<script lang="ts" setup>
import { defineProps } from "vue";
const props = defineProps(['userInfo', 'gameId']);
</script>
复制代码
构造函数进行检查 给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', '点了我');
};
</script>
复制代码
<Comp @kk="handleClick"/>
<script lang="ts" setup>
const handleClick = (data) => {
console.log(data)
}
</script>
复制代码
获取上下文
在标准组件写法里,setup 函数默认支持两个入参:
参数类型含义propsobject由父组件传递下来的数据contextobject组件的执行上下文
在setup script 中使用useContext获取上下文:
<script lang="ts" setup>
import { useContext } from 'vue'
const { slots, attrs } = useContext();
</script>
复制代码
获取到的slots,attrs跟setup里面的是一样的。
- 上一篇:Vue3快速入门
- 下一篇:分享 15 个 Vue3 全家桶开发的避坑经验
相关推荐
- Vue 技术栈(全家桶)(vue technology)
-
Vue技术栈(全家桶)尚硅谷前端研究院第1章:Vue核心Vue简介官网英文官网:https://vuejs.org/中文官网:https://cn.vuejs.org/...
- vue 基础- nextTick 的使用场景(vue的nexttick这个方法有什么用)
-
前言《vue基础》系列是再次回炉vue记的笔记,除了官网那部分知识点外,还会加入自己的一些理解。(里面会有部分和官网相同的文案,有经验的同学择感兴趣的阅读)在开发时,是不是遇到过这样的场景,响应...
- vue3 组件初始化流程(vue组件初始化顺序)
-
学习完成响应式系统后,咋们来看看vue3组件的初始化流程既然是看vue组件的初始化流程,咋们先来创建基本的代码,跑跑流程(在app.vue中写入以下内容,来跑流程)...
- vue3优雅的设置element-plus的table自动滚动到底部
-
场景我是需要在table最后添加一行数据,然后把滚动条滚动到最后。查网上的解决方案都是读取html结构,暴力的去获取,虽能解决问题,但是不喜欢这种打补丁的解决方案,我想着官方应该有相关的定义,于是就去...
- Vue3为什么推荐使用ref而不是reactive
-
为什么推荐使用ref而不是reactivereactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代optionapi的data的替...
- 9、echarts 在 vue 中怎么引用?(必会)
-
首先我们初始化一个vue项目,执行vueinitwebpackechart,接着我们进入初始化的项目下。安装echarts,npminstallecharts-S//或...
- 无所不能,将 Vue 渲染到嵌入式液晶屏
-
该文章转载自公众号@前端时刻,https://mp.weixin.qq.com/s/WDHW36zhfNFVFVv4jO2vrA前言...
- vue-element-admin 增删改查(五)(vue-element-admin怎么用)
-
此篇幅比较长,涉及到的小知识点也比较多,一定要耐心看完,记住学东西没有耐心可不行!!!一、添加和修改注:添加和编辑用到了同一个组件,也就是此篇文章你能学会如何封装组件及引用组件;第二能学会async和...
- 最全的 Vue 面试题+详解答案(vue面试题知识点大全)
-
前言本文整理了...
- 基于 vue3.0 桌面端朋友圈/登录验证+60s倒计时
-
今天给大家分享的是Vue3聊天实例中的朋友圈的实现及登录验证和倒计时操作。先上效果图这个是最新开发的vue3.x网页端聊天项目中的朋友圈模块。用到了ElementPlus...
- 不来看看这些 VUE 的生命周期钩子函数?| 原力计划
-
作者|huangfuyk责编|王晓曼出品|CSDN博客VUE的生命周期钩子函数:就是指在一个组件从创建到销毁的过程自动执行的函数,包含组件的变化。可以分为:创建、挂载、更新、销毁四个模块...
- Vue3.5正式上线,父传子props用法更丝滑简洁
-
前言Vue3.5在2024-09-03正式上线,目前在Vue官网显最新版本已经是Vue3.5,其中主要包含了几个小改动,我留意到日常最常用的改动就是props了,肯定是用Vue3的人必用的,所以针对性...
- Vue 3 生命周期完整指南(vue生命周期及使用)
-
Vue2和Vue3中的生命周期钩子的工作方式非常相似,我们仍然可以访问相同的钩子,也希望将它们能用于相同的场景。...
- 救命!这 10 个 Vue3 技巧藏太深了!性能翻倍 + 摸鱼神器全揭秘
-
前端打工人集合!是不是经常遇到这些崩溃瞬间:Vue3项目越写越卡,组件通信像走迷宫,复杂逻辑写得脑壳疼?别慌!作为在一线摸爬滚打多年的老前端,今天直接甩出10个超实用的Vue3实战技巧,手把...
- 怎么在 vue 中使用 form 清除校验状态?
-
在Vue中使用表单验证时,经常需要清除表单的校验状态。下面我将介绍一些方法来清除表单的校验状态。1.使用this.$refs...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Vue 技术栈(全家桶)(vue technology)
- vue 基础- nextTick 的使用场景(vue的nexttick这个方法有什么用)
- vue3 组件初始化流程(vue组件初始化顺序)
- vue3优雅的设置element-plus的table自动滚动到底部
- Vue3为什么推荐使用ref而不是reactive
- 9、echarts 在 vue 中怎么引用?(必会)
- 无所不能,将 Vue 渲染到嵌入式液晶屏
- vue-element-admin 增删改查(五)(vue-element-admin怎么用)
- 最全的 Vue 面试题+详解答案(vue面试题知识点大全)
- 基于 vue3.0 桌面端朋友圈/登录验证+60s倒计时
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- node卸载 (33)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- exceptionininitializererror (33)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)