黑森林有鹿 發表於 2021-10-5 08:41:00

Vite+Vue3+TypeScript学习笔记

<p>1、学习背景<br>
随着前端web应用的需求不断发展和变化,vue生态圈也紧跟开发者步伐,不断演化。尽管vue2.0已经很完善了,很多人掌握的vue2.0,感觉实在学不动了,意料之外的是尤先生继续更新vue到3.0版本,以补充vue2.0的不足之处。随着vue3.0问世,vite2.5.1也油然而生,vue始终没有放弃对项目响应速度和编译速度的追求,vite的到来,对于前端开发者而言,简直不要太幸福了。vue3.0不仅全面支持TypeScript语法,还对生命周期钩子进行了优化和剔除,加上工具setup的语法糖,vue单页面多个根元素的扩展,代码精简不说,还很有条理,vue3.0的出现再次提升了开发者的编码体验和幸福感。另外vue3整合typescript语言是前端未来发展的必然趋势,而生为vue家族的新成员vite也是前端技术爱好者的学习目标,赢在起点,从学习新技术开始。活到老,学到老,是一个合格前端开发者的毕生信仰。<br>
2、vite简介<br>
vite诞生是为了提升web项目运行性能,以更快的速度将应用页面展示给用户。Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。<br>
提供的驱动力:<br>
2.1、优化缓慢的服务器启动(冷启动开发服务器和正式环境响应速度);<br>
2.2、优化缓慢的项目更新(vite服务器);</p>
<p>3、vite创建项目<br>
兼容性注意:<br>
Vite 需要 Node.js 版本 &gt;= 12.0.0。<br>
必须安装Volar插件,用vscode编辑器<br>
// 安装vite<br>
1、npm init vite@latest</p>
<p>// 安装vite同时创建vite项目<br>
2、npm init vite@latest my-vue-app --template vue<br>
{<br>
"scripts": {<br>
"dev": "vite", // 启动开发服务器<br>
"build": "vite build", // 为生产环境构建产物<br>
"serve": "vite preview" // 本地预览生产构建产物<br>
}<br>
}<br>
4、版本依赖兼容和项目目录介绍<br>
package.json版本依赖说明, 这里是整个项目依赖版本配置,相关安装指令后面视频中会逐个教大家如何安装。<br>
注意:vuex和router都是4.0及以上版本的,否则用vue3时,找不到暴露的api<br>
{<br>
"name": "vite-ts-vue3-plus-demo",<br>
"version": "0.0.0",<br>
"scripts": {<br>
"dev": "vite",<br>
"build": "vue-tsc --noEmit &amp;&amp; vite build",<br>
"serve": "vite preview"<br>
},<br>
"dependencies": {<br>
"@element-plus/icons": "0.0.11",<br>
"dotenv": "^10.0.0",<br>
"element-plus": "^1.1.0-beta.7",<br>
"vue": "^3.0.5",<br>
"vue-router": "^4.0.11",<br>
"vuex": "^4.0.2"<br>
},<br>
"devDependencies": {<br>
"@types/node": "^16.7.1",<br>
"@vitejs/plugin-vue": "^1.3.0",<br>
"@vue/compiler-sfc": "^3.0.5",<br>
"node-sass": "^6.0.1",<br>
"sass": "^1.38.1",<br>
"sass-loader": "^12.1.0",<br>
"typescript": "^4.3.2",<br>
"vite": "^2.4.4",<br>
"vue-tsc": "^0.2.2"<br>
}<br>
}<br>
5、setup语法糖使用<br>
5.1 setup前身组合式API(基础用法)<br>
注意:在setup()中不能用this<br>
在 <code>setup</code> 中你应该避免使用 <code>this</code>,因为它不会找到组件实例。<code>setup</code> 的调用发生在 <code>data</code> property、<code>computed</code> property 或 <code>methods</code> 被解析之前,所以它们无法在 <code>setup</code> 中被获取,这也是为了避免setup()和其他选项式API混淆。<br>
/* 参数说明</p>
<ul>
<li>props 是响应式的,当传入新的 prop 时,它将被更新</li>
<li>context 是一个普通的上下文JavaScript对象,它暴露组件的三个 property(包括属性,插槽,方法),</li>
<li>如下示例1所示<br>
*/<br>
// 示例1</li>
</ul>

<p>5.2 setup后世(高级用法),推荐用法<br>
注意:defineProps不需要引入,vue单文件内部自动暴露的API</p>

<p>// 高级用法</p>

<p>6、defineProps 和 defineEmits<br>
注意:defineProps 和 defineEmits 都是只在
6.2 、父组件vue

<template>
        <testpropspmit :msg="msg" @on-change="handleChange"></testpropspmit>
</template>
温馨提示:这里介绍一哈volar插件小图标在vue文件里的作用:
点击这个三角形图标,会将文件归类显示,方便编写代码;
</p><p>7、正确使用defineExpose<br>
使用
</p><p>7.2、父组件调用子组件方法和属性<br>
<template><br>
&lt;TestPropsEmit ref="propsEmitRef" :msg='msg' @on-change="handleChange"&gt;                 <br>
</template></p>

<p>7.3 在setup如何定义变量(字符串,对象,数组)<br>
<template><br>
<h2>{{count}} {{user.name}}</h2><br>
<span v-for="(item, index) in arr" :key="index">{{item}}</span><br>
&lt;button @click="setName"&gt;点击我增加<br>
</template></p>

<p>8、Watch和WatchEffect<br>
1、基本使用方法:<br>
<template><br>
<p>{{originData.count}}{{originData.user.name}}</p><br>
<p v-for="(item, index) in originData.arr" :key="index">{{item}}</p><br>
&lt;button @click="incriment"&gt;点击我count增加<br>
</template></p>

<p>2、watch与 watchEffect 比较,推荐watch监听<br>
watch: 页面更新后不会立即执行,而watchEffect 它会执行;<br>
如果要实现:watch在页面更新之后就执行,需要增加立即执行的属性;<br>
watch(, (n, o)=&gt; {console.log(n,n.name)}, {deep: true, immediate: true})<br>
1、watch和watchEffect都懒执行副作用,不过watchEffect比较频繁,在vue组件更新之前执行;<br>
2、watch更具体地说明什么状态应该触发侦听器重新运行,watchEffect就没有这么友好;<br>
3、watch访问侦听状态变化前后的值。<br>
9、在setup中的生命周期钩子<br>
因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。<br>
下表包含如何在 setup () 内部调用生命周期钩子:<br>
选项式 APIHook inside setup<br>
beforeCreateNot needed*    不需要<br>
createdNot needed*    不需要<br>
beforeMountonBeforeMount 挂载之前<br>
mountedonMounted    页面加载完成时执行<br>
beforeUpdateonBeforeUpdate<br>
updatedonUpdated<br>
beforeUnmountonBeforeUnmount<br>
unmountedonUnmounted页面销毁时执行<br>
errorCapturedonErrorCaptured<br>
renderTrackedonRenderTracked<br>
renderTriggeredonRenderTriggered<br>
activatedonActivated<br>
deactivatedonDeactivated</p>

<p>10、用Ts限制define(Emits|Props)参数类型<br>
注意:<br>
1、在setup语法糖中引入组件不需要注册声明就可以直接用了<br>
2、ts 限制组件传参类型,默认是必须传值的,否则控制台出现警告, 引入组件的地方会出现红色提醒,不想必传在绑定参数后加?即可<br>
3、ts传参支持多种类型校验,一个参数可以传字符串,数组,Boolean等<br>
4、用ts方式限制defineEmits和defineProps参数类型<br>
1、子组件<br>
<template><br>
<h1>{{msg}}</h1><br>
<h3>{{title}}</h3><br>
&lt;input v-model="inputValue" type="text" @blur="handleUpdate($event)"&gt;<br>
</template></p>

<p>2、父组件</p>

<template>
    <cellsample @update="update"></cellsample>
</template>
<p>11、递归组件<br>
一个单文件组件可以通过它的文件名被其自己所引用。例如:名为 FooBar.vue 的组件可以在其模板中用 <foobar> 引用它自己。<br>
请注意这种方式相比于 import 导入的组件优先级更低。如果有命名的 import 导入和组件的推断名冲突了,可以使用 import 别名导入:<br>
import { FooBar as FooBarChild } from './components'<br>
注意:这里有小问题,当单文件引入单文件时会出现内存溢出现象<br>
12、component动态组件<br>
由于组件被引用为变量而不是作为字符串键来注册的,在
<template>
<component :is="Foo">
<component :is="someCondition ? Foo : Bar">
</component></component></template>
13、ts限制普通函数/箭头函数参数类型
13.1普通函数

13.2箭头函数,推荐用法

14、引入vuex配置和使用
14.1 创建项目时我们已经引入了vuex4.0版本,接下来我们就开始配置vuex4.0并测试。
// 注意必须安装vuex4.0版本及以上
npm install vuex@next --save
#or
yarn add vuex@next --save
14.2 在src目录下创建store文件夹,新建文件index.ts, index.ts内容如下所示:
import { InjectionKey } from 'vue'
/**
* 引入 InjectionKey 并将其传入 useStore 使用过的任何地方,
* 很快就会成为一项重复性的工作。为了简化问题,可以定义自己
* 的组合式函数来检索类型化的 store
*/
// 未简化useStore版
// import { createStore, Store } from 'vuex'
// 简化useStore版
import { useStore as baseUseStore, createStore, Store} from 'vuex'
</foobar></p><p>// 为 store state 声明类型<br>
export interface State {<br>
username: string,<br>
count: number<br>
}</p>
<p>// 定义 injection key<br>
export const key: InjectionKey&lt;Store<state>&gt; = Symbol()</state></p>
<p>// 导出store模块<br>
export const store = createStore<state>({<br>
state: {<br>
username: "测试store",<br>
count: 0<br>
},<br>
getters:{<br>
getName: state =&gt;{<br>
return state.username<br>
}<br>
},<br>
mutations: {<br>
// 重置名称<br>
SET_NAME(state, params:string) {<br>
state.username = params<br>
}<br>
},<br>
actions:{}<br>
})</state></p>
<p>// 定义自己的 <code>useStore</code> 组合式函数<br>
export function useStore () {<br>
return baseUseStore(key)<br>
}<br>
14.3 在根目录下新建vuex-d.ts文件,内容如下所示:<br>
// 一个声明文件来声明 Vue 的自定义类型 ComponentCustomProperties<br>
import { ComponentCustomProperties } from 'vue';<br>
import { Store } from 'vuex';</p>
<p>declare module '@vue/runtime-core' {<br>
// 声明自己的 store state<br>
interface State {<br>
count: number,<br>
username: string<br>
}<br>
// 为 <code>this.$store</code> 提供类型声明<br>
interface ComponentCustomProperties {<br>
$store: Store<state><br>
}<br>
}<br>
14.4在main.ts中注入store模块<br>
import { createApp } from 'vue';<br>
import App from './App.vue';<br>
// 导入store模块, 传入 injection key<br>
import { store, key } from '@/store';<br>
const app = createApp(App)<br>
app.use(store, key)<br>
app.mount('#app')<br>
14.5引用测试vuex配置是否正确<br>
&lt;el-button @click="changeName" size="small"&gt;点击修改名称</state></p>

<p>15、router配置以及使用详解<br>
15.1 安装<br>
创建项目时我们已经引入了router4.0版本,接下来我们就开始配置router4.0并测试。<br>
// 注意:安装router必须是4.0及以上<br>
npm install vue-router@4<br>
15.2   页面准备<br>
目录结构</p>
<p>页面具体内容:<br>
1、layout/index.vue<br>
<template><br>
<header><br>
<router-view></router-view><br>
</header></template></p>

<p>2、layout/header/index.vue<br>
<template><br>
<div class="action"><br>
&lt;h2 @click="handleClick(1)"&gt;首页<br>
&lt;h2 @click="handleClick(0)"&gt;关于<br>
</div><br>
</template></p>

<style>.action { display: flex }
h2 { padding: 0 10px; cursor: pointer }
h2:hover { color: rgba(255, 0, 0, 1) }</style>
<p>3、pages/home/index.vue<br>
<template><br>
<h2>home</h2><br>
</template><br>
4、pages/about/index.vue<br>
<template><br>
<h2>about</h2><br>
</template><br>
15.3 在src目录下创建router文件夹,然后创建index.ts文件,内容如下所示:<br>
import { createRouter, createWebHashHistory } from "vue-router";<br>
import LayOut from "../components/layout/index.vue";</p>
<p>const routes = [<br>
{<br>
path: '/',<br>
component: LayOut,<br>
redirect: '/home',<br>
children:[<br>
{<br>
path: '/home',<br>
name: 'home',<br>
component: ()=&gt; import("../pages/home/index.vue"),<br>
meta:{<br>
title: '首页',<br>
icon: ''<br>
}<br>
},<br>
{<br>
path: '/about',<br>
name: 'about',<br>
component: ()=&gt; import("../pages/about/index.vue"),<br>
meta:{<br>
title: '关于',<br>
icon: ''<br>
}<br>
}<br>
]<br>
}<br>
]<br>
const router = createRouter({<br>
history: createWebHashHistory(),<br>
routes<br>
})<br>
export default router<br>
15.4 在main.ts中注入router模块, 重新启动项目,访问路由,看是否正确<br>
import { createApp } from 'vue'<br>
import App from './App.vue'<br>
import { store, key } from './store';<br>
import router from './router';</p>
<p>const app = createApp(App);<br>
app.use(store, key);<br>
app.use(router);<br>
app.mount('#app');<br>
15.5使用路由<br>
<template><br>
<div class="action"><br>
&lt;h2 @click="handleClick(1)"&gt;首页<br>
&lt;h2 @click="handleClick(0)"&gt;关于<br>
</div><br>
</template></p>

<style>.action { display: flex }
h2 { padding: 0 10px; cursor: pointer }
h2:hover { color: rgba(255, 0, 0, 1) }</style>
<p>16、引入element-plus以及注意事项<br>
16.1 安装<br>
npm install element-plus --save</p>
<h1 id="or">or</h1>
<p>yarn add element-plus</p>
<h1 id="安装icon图标依赖库">安装icon图标依赖库</h1>
<p>npm install @element-plus/icons</p>
<h1 id="or-1">or</h1>
<p>yarn add @element-plus/icons<br>
16.2 在main.ts 文件中引入配置<br>
import { createApp } from 'vue'<br>
import App from './App.vue'<br>
import { store, key } from './store';<br>
// 注入路由<br>
import router from './router';</p>
<p>// 引入ui组件<br>
import ElementPlus from 'element-plus'<br>
import 'element-plus/dist/index.css'</p>
<p>const app = createApp(App);<br>
app.use(store, key);<br>
app.use(router);<br>
app.use(ElementPlus);<br>
app.mount('#app');<br>
16.3 在vue文件中引用ui组件<br>
1、单个图标引用<br>
<template><br>
<el-icon :size="20" :color="'blue'"><br>
<edit><br>
</edit></el-icon><br>
</template></p>

<p>2、全局注册图标使用<br>
import { createApp } from 'vue'<br>
import App from './App.vue'</p>
<p>import { Edit,Search } from '@element-plus/icons'</p>
<p>const app = createApp(App);<br>
app.component("edit", Edit)<br>
app.component("search", Search)<br>
app.mount('#app');<br>
2、1 使用图标<br>
<template><br>
<h2>home页面</h2><br>
<el-button type="primary">主要按钮</el-button><br>
<el-button type="success">成功按钮</el-button><br>
<el-icon :size="20" :color="'blue'"><br>
<edit><br>
</edit></el-icon><br>
<el-icon :size="20"><br>
<search></search><br>
</el-icon><br>
</template></p>

<p>17、配置vite.config.ts<br>
这里主要配置vite服务器的打包保存地址,打包分解,端口号,是否自动打开浏览器,远程请求地址代理目标,目录别名,全局样式配置等。<br>
import { defineConfig } from 'vite';<br>
import vue from '@vitejs/plugin-vue';<br>
import { loadEnv } from 'vite';<br>
// nodejs写法,获取项目目录<br>
import path from 'path';</p>
<p>// https://vitejs.dev/config/<br>
export default({ command, mode }) =&gt; {<br>
return defineConfig({<br>
plugins: ,<br>
server:{<br>
host: '127.0.0.1',<br>
port: Number(loadEnv(mode, process.cwd()).VITE_APP_PORT),<br>
strictPort: true, // 端口被占用直接退出<br>
https: false,<br>
open: true,// 在开发服务器启动时自动在浏览器中打开应用程序<br>
proxy: {<br>
// 字符串简写写法<br>
// '/foo': '',<br>
// 选项写法<br>
'/api': {<br>
target: loadEnv(mode, process.cwd()).VITE_APP_BASE_URL,<br>
changeOrigin: true,<br>
rewrite: (path) =&gt; path.replace(/^/api/, '')<br>
},<br>
// 正则表达式写法<br>
// '^/fallback/.<em>': {<br>
//   target: 'http://jsonplaceholder.typicode.com',<br>
//   changeOrigin: true,<br>
//   rewrite: (path) =&gt; path.replace(/^/fallback/, '')<br>
// },<br>
},<br>
hmr:{<br>
overlay: true // 屏蔽服务器报错<br>
}<br>
},<br>
resolve:{<br>
alias:{<br>
'@': path.resolve(__dirname,'./src')<br>
}<br>
},<br>
css:{<br>
// css预处理器<br>
preprocessorOptions: {<br>
// 引入 var.scss 这样就可以在全局中使用 var.scss中预定义的变量了<br>
// 给导入的路径最后加上 ;<br>
scss: {<br>
additionalData: '@import "@/assets/styles/global.scss";'<br>
}<br>
}<br>
},<br>
build:{<br>
chunkSizeWarningLimit: 1500, // 分块打包,分解块,将大块分解成更小的块<br>
rollupOptions: {<br>
output:{<br>
manualChunks(id) {<br>
if (id.includes('node_modules')) {<br>
return id.toString().split('node_modules/').split('/').toString();<br>
}<br>
}<br>
}<br>
}<br>
}<br>
})<br>
}<br>
18、tsconfig.json 配置<br>
这是typescript的识别配置文件,也是ts向js转化的中间站,这里配置了许多关于ts的文件类型和策略方法。<br>
{<br>
"compilerOptions": {<br>
"target": "esnext",<br>
"module": "esnext",<br>
"moduleResolution": "node",<br>
"strict": true,<br>
"jsx": "preserve",<br>
"sourceMap": true,<br>
"resolveJsonModule": true,<br>
"esModuleInterop": true,<br>
"lib": ["esnext", "dom"],<br>
"baseUrl": ".",<br>
"paths": {<br>
"@/</em>":["src/<em>"]<br>
}<br>
},<br>
"include": ["src/**/</em>.ts", "src/<strong>/*.d.ts", "src/</strong>/<em>.tsx", "src/**/</em>.vue"]<br>
}<br>
19、shims-vue.d.ts配置, 声明vue文件全局模块<br>
这里是配置声明,比如css,vue等文件,ts不能识别,需要配置声明模块类型。<br>
declare module '*.vue' {<br>
import { DefineComponent } from 'vue'<br>
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types<br>
const component: DefineComponent&lt;{}, {}, any&gt;<br>
export default component<br>
}<br>
20、安装scss并配置全局样式文件<br>
// 注意要使用scss,必须安装依赖,否则报错<br>
npm install node-sass sass-loader sass -D<br>
20.1需要在src目录的assets静态目录新增一个全局global.scss文件,其他样式文件导入到该文件即可全局使用和修改。</p>
<p>或者在global.scss写一个单独属性测试<br>
$color-primary: #007aff;<br>
vue使用全局样式变量<br>
<template><br>
<h2 class="test-color">home页面</h2><br>
</template></p>
<style lang="scss" scoped="">.test-color { }</style>
<p>20.2在vite.config.ts 文件中配置global.scss<br>
css:{<br>
// css预处理器<br>
preprocessorOptions: {<br>
// 引入 var.scss 这样就可以在全局中使用 var.scss中预定义的变量了<br>
// 给导入的路径最后加上 ;<br>
scss: {<br>
additionalData: '@import "@/assets/styles/global.scss";'<br>
}<br>
}<br>
}<br>
21、响应式API<br>
响应式状态需要明确使用响应式 APIs 来创建。和从 setup() 函数中返回值一样,ref 值在模板中使用的时候会自动解包:</p>

<template>
<button @click="count++">{{ count }}</button>
</template>
22、.env.环境变量配置和读取
环境变量建议放到项目根目录下, 方便vite.config.ts文件读取和使用
.env.production // 生产环境配置文件
.env.development // 开发环境配置文件
22.1 生产和开发环境配置文件内容如下:
写变量时一定要以VITE_开头,才能暴露给外部读取
# 开发环境 / #生产环境
VITE_APP_TITLE = "前端技术栈"
VITE_APP_PORT = 3001
<h1 id="请求接口">请求接口</h1>
<p>VITE_APP_BASE_URL = "http://39.12.29.12:8080"</p>
<p>//env.d.ts文件内进行 环境变量智能提示配置<br>
interface ImportMetaEnv {<br>
VITE_APP_TITLE: string,<br>
VITE_APP_PORT: string,<br>
VITE_APP_BASE_URL: string<br>
}<br>
22.2 vite.config.ts 读取配置文件<br>
import { defineConfig } from 'vite';<br>
import vue from '@vitejs/plugin-vue';<br>
import { loadEnv } from 'vite';<br>
// nodejs写法,获取项目目录<br>
import path from 'path';</p>
<p>// https://vitejs.dev/config/<br>
export default({ command, mode }) =&gt; {<br>
// console.log(command, mode, 5555);<br>
return defineConfig({<br>
plugins: ,<br>
server:{<br>
host: '127.0.0.1',<br>
port: Number(loadEnv(mode, process.cwd()).VITE_APP_PORT),<br>
strictPort: true, // 端口被占用直接退出<br>
https: false,<br>
open: true,// 在开发服务器启动时自动在浏览器中打开应用程序<br>
proxy: {<br>
// 字符串简写写法<br>
// '/foo': '',<br>
// 选项写法<br>
'/api': {<br>
target: loadEnv(mode, process.cwd()).VITE_APP_BASE_URL,<br>
changeOrigin: true,<br>
rewrite: (path) =&gt; path.replace(/^/api/, '')<br>
},<br>
// 正则表达式写法<br>
// '^/fallback/.*': {<br>
//   target: 'http://jsonplaceholder.typicode.com',<br>
//   changeOrigin: true,<br>
//   rewrite: (path) =&gt; path.replace(/^/fallback/, '')<br>
// },<br>
// 使用 proxy 实例<br>
// '/api': {<br>
//   target: 'http://jsonplaceholder.typicode.com',<br>
//   changeOrigin: true,<br>
//   configure: (proxy, options) =&gt; {<br>
//   // proxy 是 'http-proxy' 的实例<br>
//   },<br>
// }<br>
},<br>
hmr:{<br>
overlay: true // 屏蔽服务器报错<br>
}<br>
},<br>
resolve:{<br>
alias:{<br>
'@': path.resolve(__dirname,'./src')<br>
}<br>
},<br>
css:{<br>
// css预处理器<br>
preprocessorOptions: {<br>
// 引入 var.scss 这样就可以在全局中使用 var.scss中预定义的变量了<br>
// 给导入的路径最后加上 ;<br>
scss: {<br>
additionalData: '@import "@/assets/styles/global.scss";'<br>
},<br>
sass: {<br>
additionalData: '@import "@/assets/styles/global.scss";'<br>
}<br>
}<br>
},<br>
build:{<br>
chunkSizeWarningLimit: 1500, // 分块打包,分解块,将大块分解成更小的块<br>
rollupOptions: {<br>
output:{<br>
manualChunks(id) {<br>
if (id.includes('node_modules')) {<br>
return id.toString().split('node_modules/').split('/').toString();<br>
}<br>
}<br>
}<br>
}<br>
}<br>
})<br>
}<br>
22.3 其他文件读取环境变量<br>
<template><br>
首页内容展示<br>
</template></p>

<p>附上学习视频:<br>
https://www.bilibili.com/video/BV1QP4y1p748?spm_id_from=333.999.0.0</p><br><br>
来源:https://www.cnblogs.com/KaypoGeng/p/15367915.html
頁: [1]
查看完整版本: Vite+Vue3+TypeScript学习笔记