基础语法
定义data
< 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
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
}
} ,
} )
定义methods
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
}
} )
vue-router
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 ( '../views/About.vue' )
}
] ;
const router = createRouter ( {
history: createWebHistory ( process. env. BASE_URL ) ,
routes
} ) ;
export default router;
扩展路由额外属性
type RouteConfig = RouteRecordRaw & { hidden? : boolean} ;
const routes: Array< RouteConfig> = [
{
path: '/' ,
name: 'Home' ,
component: Home,
hidden: true ,
meta: {
permission: true ,
icon: ''
}
}
] ;
在setup中使用
import { useRouter } from 'vue-router' ;
import { defineComponent } from 'vue' ;
export default defineComponent ( {
setup ( ) {
const router = useRouter ( ) ;
goRoute ( path ) {
router. push ( { path} )
}
}
} )
vuex#####
使用this.$store
import { createStore } from 'vuex';
export type State = {
count: number
}
export default createStore({
state: {
count: 0
}
});
import { ComponentCustomProperties} from 'vue' ;
import { Store} from 'vuex' ;
import { State} from './store'
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$store: Store< State>
}
}
在setup中使用
import { InjectionKey } from 'vue' ;
import { createStore, Store } from 'vuex' ;
export type State = {
count: number
}
export const key: InjectionKey< Store< State>> = Symbol ( 'key' ) ;
import store, { key } from './store' ;
app. use ( store, key) ;
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的对象,接收两个泛型约束 第一个是该模块类型
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> ;
export type State = {
count: number,
todo? : TodoState
}
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
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;
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。
导出方法
const handleClick = ( type: string ) => {
console. log ( type) ;
}
定义props
使用props需要用到defineProps来定义,具体用法跟之前的props写法类似: 基础用法
import { defineProps } from "vue";
const props = defineProps(['userInfo', 'gameId']);
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
import { defineEmit } from 'vue' ;
const emit = defineEmit ( [ 'kk' , 'up' ] ) ;
const handleClick = ( ) => {
emit ( 'kk' , '点了我' ) ;
} ;
< Comp @kk= "handleClick" / >
< script lang= "ts" setup>
const handleClick = ( data ) => {
console. log ( data)
}
< / script>
获取上下文
在标准组件写法里,setup 函数默认支持两个入参: 在setup script 中使用useContext获取上下文:
import { useContext } from 'vue'
const { slots, attrs } = useContext ( ) ;
获取到的slots,attrs跟setup里面的是一样的。
参考地址