vue3的那些事
沒有特別的幸運,那么就特別的努力!!!
vue3 + vite + ts + vant + axios + sass 移動端h5搭建新項目
- vue3 + vite + ts + vant + axios + sass
- 搭建第一個 Vite 項目 (vite + vue + ts)
- nvm管理node多版本。[^1]
- 代碼規范 (格式化、提示)
- eslint
- prettier
- 配置eslintrc
- 配置 tsconfig
- CSS 預處理器
- less安裝使用
- sass安裝使用
- vant 安裝
- Rem 布局適配
- 底部適配 - 對于ios系統
- vue-router
- Axios
- 示例頁面
- 項目地址
- vue3 開發
- 父組件傳參
- defineProps
- withDefaults 定義默認值
- defineEmits
- ref VS reactive
- watch
- 監聽ref定義的一個響應式數據
- 監聽多個ref
- 監聽reactive 定義響應式對象的單一屬性
- watch VS watchEffect
- 生命周期
- keep-alive 緩存組件
- provide/inject
vue3 + vite + ts + vant + axios + sass
vite官網:
搭建第一個 Vite 項目 (vite + vue + ts)
兼容性注意
Vite 需要 Node.js 版本 14.18+,16+。然而,有些模板需要依賴更高的 Node 版本才能正常運行,當你的包管理器發出警告時,請注意升級你的 Node 版本。
nvm管理node多版本。1
// 搭建第一個 Vite 項目 (vite + vue + ts)// npm (本篇采用npm搭建) npm init vite@latest // yarn yarn create vite// pnpm pnpm create vite # npm 6.x npm create vite@latest vite-vue3 --template vue# npm 7+, extra double-dash is needed: npm create vite@latest vite-vue3 -- --template vue# yarn yarn create vite vite-vue3 --template vue# pnpm pnpm create vite vite-vue3 --template vue項目啟動
cd vite-vue3npm install npm run dev代碼規范 (格式化、提示)
eslint
# 自動生成配置文件并安裝下面四個依賴 npx eslint --init# 或者手動創建文件 # npm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue -Dprettier
npm i prettier eslint-config-prettier eslint-plugin-prettier -D創建prettier文件
// prettier.cjsmodule.exports = {printWidth: 100,tabWidth: 2,useTabs: false, // 是否使用tab進行縮進,默認為falsesingleQuote: true, // 是否使用單引號代替雙引號,默認為falsesemi: true, // 行尾是否使用分號,默認為truearrowParens: 'always',endOfLine: 'auto',vueIndentScriptAndStyle: true,htmlWhitespaceSensitivity: 'strict', };配置eslintrc
// eslintrc.cjsmodule.exports = {root: true, // 停止向上查找父級目錄中的配置文件env: {browser: true,es2021: true,node: true,},extends: ['eslint:recommended','plugin:vue/vue3-essential','plugin:@typescript-eslint/recommended','plugin:prettier/recommended','prettier', // eslint-config-prettier 的縮寫],parser: 'vue-eslint-parser', // 指定要使用的解析器// 給解析器傳入一些其他的配置參數parserOptions: {ecmaVersion: 'latest', // 支持的es版本parser: '@typescript-eslint/parser',sourceType: 'module', // 模塊類型,默認為script,我們設置為module},plugins: ['vue', '@typescript-eslint', 'prettier'], // eslint-plugin- 可以省略rules: {'vue/multi-word-component-names': 'off','@typescript-eslint/no-var-requires': 'off',}, };配置 tsconfig
// tsconfig.json{"compilerOptions": {"target": "ESNext","useDefineForClassFields": true,"module": "ESNext","moduleResolution": "Node","strict": true,"jsx": "preserve","sourceMap": true,"resolveJsonModule": true,"isolatedModules": true,"esModuleInterop": true,"lib": ["ESNext", "DOM"],"skipLibCheck": true,// 👆是初始化默認配置/*在ts中導入js模塊會報錯找不到類型聲明解決方法一:僅設置 "allowJs": true 即可注:allowJs設置true時,下方include不可以加入'src/**\/*.js',否則報錯'無法寫入文件xx因為它會覆蓋輸入文件'方法二:僅在 env.d.ts 中加入 declare module '*.js'; 模塊定義即可總結:和 "include": ["src/**\/*.js"] 沒有任何關系*/"allowJs": true, // 允許編譯器編譯JS,JSX文件"baseUrl": "./",// "typeRoots": [// "node_modules/@types" // 默認會從'node_modules/@types'路徑去引入聲明文件// ],// "types": ["node"] // 僅引入'node'模塊// "paths"是相對于"baseUrl"進行解析// 在vite.config里配置了路徑別名resolve.alias,為了讓編譯 ts 時也能夠解析對應的路徑,我們還需要配置 paths 選項"paths": {"@/*": ["src/*"],}},"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],// references屬性是 TypeScript 3.0 的新特性,允許將 TypeScript 程序拆分結構化(即拆成多個文件,分別配置不同的部分)。"references": [{ "path": "./tsconfig.node.json" }] }tsconfig.node.json
{"compilerOptions": {"composite": true,"module": "ESNext","moduleResolution": "Node","allowSyntheticDefaultImports": true},"include": ["vite.config.ts", "config/index.ts"] }CSS 預處理器
less安裝使用
// npm 安裝 npm install less npm install less-loader// yarn 安裝 yarn add less less-loader // 使用 < style lang="less" scoped></ style>sass安裝使用
// npm 安裝 npm install -D sass sass-loader// yarn 安裝 yarn add sass sass-loader <style lang="scss" scoped> .home {background-color: #eee;height: 100vh; } </style>vant 安裝
vant3官網地址:
安裝
常規用法
import { createApp } from 'vue' import './style.css' // 1. 引入你需要的組件 import { Button } from 'vant'; // 2. 引入組件樣式 import 'vant/lib/index.css'; import App from './App.vue'const app = createApp(App)// 3. 注冊你需要的組件 app.use(Button);app.mount('#app');按需引入組件樣式
// 通過 npm 安裝 npm i unplugin-vue-components -D// 通過 yarn 安裝 yarn add unplugin-vue-components -D// 通過 pnpm 安裝 pnpm add unplugin-vue-components -D配置插件
vite 的項目,在 vite.config.js 文件中配置插件:
使用組件
<template><van-button type="primary" /> </template>Rem 布局適配
// npm 安裝 npm install -D postcss-pxtorem lib-flexible// yarn 安裝 yarn add postcss-pxtorem lib-flexible根目錄下面新建一個 postcss.config.js 文件
// postcss.config.js module.exports = {plugins: {'postcss-pxtorem': {rootValue: 37.5,propList: ['*'],},}, };底部適配 - 對于ios系統
<!-- 在 head 標簽中添加 meta 標簽,并設置 viewport-fit=cover 值 --> <metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" /><!-- 開啟頂部安全區適配 --> <van-nav-bar safe-area-inset-top /><!-- 開啟底部安全區適配 --> <van-number-keyboard safe-area-inset-bottom />vue-router
1.安裝
npm i vue-router@42.創建路由
// src/router/index.ts//現在創建router的方式與vue2.x的版本已經很不同了 import { createRouter, createWebHashHistory } from "vue-router"; import { routes } from "./routes";const router = createRouter({history: createWebHashHistory(), //替代之前的mode,是必須的routes, });router.beforeEach((to, from, next) => {document.title = to.meta.title as string || '浙里普法'next() }) export default router; // src/router/routes.tsimport { RouteRecordRaw } from "vue-router"; export const routes: Array<RouteRecordRaw> = [{path: "/",redirect: "/index",},{path: "/index",name: "Index",component: () => import("../view/index.vue"),meta: {nav: true,title: '首頁'}},];3.掛載路由
// src/main.ts import { createApp } from 'vue'; import App from './App.vue'; import router from './router/index'; //引入vue-routerconst app = createApp(App);app.use(router); // 掛載到app上 app.mount('#app');4.使用
<template><router-view /> </template>Axios
1.安裝
// npm 安裝 npm i axios// yarn 安裝 yarn add axios // src/utils/http/axios.tsimport axios, { AxiosResponse, AxiosRequestConfig, AxiosError } from 'axios'; import type { Response } from './types'; // import { auth } from '@/utils'; import { Toast } from 'vant'; import router from '../../router';axios.defaults.baseURL = '/api'; axios.defaults.timeout = 1000 * 60; axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';// 創建axios實例 const service = axios.create({// 根據不同env設置不同的baseURLbaseURL: import.meta.env.VITE_APP_API_BASE_URL, });// axios實例攔截請求 service.interceptors.request.use((config: AxiosRequestConfig) => {config.headers = {...config.headers,// ...auth.headers(), // 你的自定義headers,如token等};return config;},(error: AxiosError) => {return Promise.reject(error);} );// axios實例攔截響應 service.interceptors.response.use(// 2xx時觸發(response: AxiosResponse<Response>) => {// response.data就是后端返回的數據,結構根據你們的約定來定義const { code, message } = response.data;let errMessage = '';switch (code) {case 0:break;case 1: // token過期errMessage = 'Token expired';router.push('/login');break;case 2: // 無權限errMessage = 'No permission';break;// default:// errMessage = message;// break;}if (errMessage) Toast.fail(errMessage);return response;},// 非2xx時觸發(error: AxiosError) => {Toast.fail('Network Error...');return Promise.reject(error);} );export type { AxiosResponse, AxiosRequestConfig };export default service; // src/utils/http/index.tsimport service, { AxiosRequestConfig } from './axios'; export * from './types';export const request = <T = any>(config: AxiosRequestConfig): Promise<T> => {return new Promise((resolve, reject) => {service.request(config).then((res) => {// 一些業務處理resolve(res.data);}).catch((err) => {console.log('request fail:', err);});}); };const http = {get<T = any>(url: string, params = {}, config?: AxiosRequestConfig): Promise<T> {return request({ url, params, ...config, method: 'GET' });},post<T = any>(url: string, data = {}, config?: AxiosRequestConfig): Promise<T> {return request({ url, data, ...config, method: 'POST' });},put<T = any>(url: string, data = {}, config?: AxiosRequestConfig): Promise<T> {return request({ url, data, ...config, method: 'PUT' });},delete<T = any>(url: string, data = {}, config?: AxiosRequestConfig): Promise<T> {return request({ url, data, ...config, method: 'DELETE' });},// 上傳文件,指定 'Content-Type': 'multipart/form-data'upload<T = any>(url: string, data = {}, config?: AxiosRequestConfig): Promise<T> {return request({url,data,...config,method: 'POST',headers: { 'Content-Type': 'multipart/form-data' },});}, };export default http; // src/utils/http/types.ts// 和后端約定好接口返回的數據結構 export interface Response<T = any> {data: string[];code: number | string;message: string;result: T; }示例頁面
banner列表頁面
<script setup> import ResourceList from '@/components/ResourceList.vue' import { monthlyResourceList } from '@/service/api/common' import { onMounted, ref } from 'vue' import { useRoute, useRouter } from "vue-router";const $route = useRoute() const $router = useRouter() const list = ref([]) const loading = ref(false); const finished = ref(false); const refreshing = ref(false); const params = ref({relationId: $route.query.id,relationType: 'banner',currentPage: 1,pageSize: 10 }) onMounted(() => {document.title = $route.query.namegetColumnResourceList() }) const getColumnResourceList = () => monthlyResourceList(params.value).then(res => {loading.value = trueif (res.success) {loading.value = falselist.value = [...list.value,...res.data]// 如果列表數據條數>=總條數,不再觸發滾動加載if (list.value.length >= res.totalCount) {finished.value = true}} }) const onRefresh = () => {params.value.currentPage = 1finished.value = false;refreshing.value = falselist.value = []getColumnResourceList(); }; const onLoad1 = () => {params.value.currentPage++getColumnResourceList() } const toInfo = row => {const { type, resourceSource, resourceId, id: relationId, relationType = 'banner' } = row$router.push({path: '/detail',query: { type, resourceSource, resourceId, relationId, relationType }}) }</script><template><div class='monthInfo'><van-pull-refresh v-model="refreshing" @refresh="onRefresh"><van-listv-model:loading="loading":finished="finished"finished-text="沒有更多了":immediate-check="false"@load="onLoad1"><div v-for="(item, i) in list" :key="i"><ResourceList :info="item" @click="toInfo(item)"></ResourceList></div></van-list></van-pull-refresh></div> </template><style lang='scss' scoped> .monthInfo {padding: 22px 16px; } </style>項目地址
為了安全協議:項目地址api 已全部替換(望理解!!!)
https://gitee.com/hammer1010_admin/vue3-vite
vue3 開發
父組件傳參
defineProps
父組件
<template><Children :msg="msg" :list="list"></Children> </template><script setup lang="ts"> import { ref, reactive } from 'vue' import Children from './Children.vue'const msg = ref('hello 啊,樹哥') const list = reactive<number[]>([1, 2, 3]) </script>子組件
<template><div><p>msg:{{msg}}</p><p>list:{{list}}</p></div> </template><script setup lang="ts"> import { defineProps } from "vue";const { msg, list } = defineProps(['msg', 'list']) </script>withDefaults 定義默認值
<script setup lang="ts"> import { defineProps } from "vue"; withDefaults(defineProps<{ msg?: (string | number | boolean), title?: string }>(),{msg:'hello vite',title:'默認標題'} );</script>defineEmits
子組件傳遞
<template><div><p>msg:{{msg}}</p><p>list:{{list}}</p><button @click="onChangeMsg">改變msg</button></div> </template><script setup lang="ts"> type Props = {msg?: string,list?: number[] }withDefaults(defineProps<Props>(), {msg: '張麻子',list: () => [4, 5, 6] })const emits = defineEmits(['changeMsg']) const onChangeMsg = () => { emits('changeMsg','黃四郎') } </script>父組件接收
<template><Children :msg="msg" :list="list" @changeMsg="changeMsg"></Children> </template><script setup lang="ts"> import { ref, reactive } from 'vue' import Children from './Children.vue'const msg = ref('hello 啊,樹哥') const list = reactive<number[]>([1, 2, 3])const changeMsg = (v: string) => {msg.value = v } </script>ref VS reactive
watch
偵聽一個或多個響應式數據源,并在數據源變化時調用所給的回調函數。
監聽ref定義的一個響應式數據
<script setup lang="ts"> import { ref, watch } from "vue";const str = ref('一個值')//3s后改變str的值 setTimeout(() => { str.value = '3s后一個值' }, 3000)watch(str, (newV, oldV) => {console.log(newV, oldV) //3s后一個值 一個值 })</script>監聽多個ref
<script setup lang="ts"> import { ref, watch } from "vue";let name = ref('樹哥') let age = ref(18)//3s后改變值 setTimeout(() => {name.value = '我叫樹哥'age.value = 19 }, 3000)watch([name, age], (newV, oldV) => {console.log(newV, oldV) // ['我叫樹哥', 19] ['樹哥', 18] })</script>監聽reactive 定義響應式對象的單一屬性
<script setup lang="ts"> import { reactive, watch } from "vue";let info = reactive({name: '張麻子',age: 18,obj: {str: '彼時彼刻,恰如此時此刻'} })//3s后改變s值 setTimeout(() => {info.obj.str = 'to be or not to be' }, 3000)// 需要自己開啟 deep:true深度監聽,不然不發觸發 watch 的回調函數 watch(() => info.obj, (newV, oldV) => {console.log(newV, oldV) }, {deep: true })</script>watch VS watchEffect
watch只有監聽的值發生變化的時候才會執行
watchEffect 立即運行一個函數,同時響應式地追蹤其依賴,并在依賴更改時重新執行。
wacthEffect 無法獲取到原值,只能得到變化后的值
watchEffect 不用指明監視哪個屬性,監視的回調中用到哪個屬性就監視哪個屬性
生命周期
keep-alive 緩存組件
作用和vue2一致,只是生命周期名稱有所更改
<template><div class="full-screen"><router-view v-slot="{ Component }"><keep-alive :include="['Index', 'secondaryPage', 'resource', 'monthInfo', 'collect']"><component :is="Component" /></keep-alive></router-view></div> </template>provide/inject
provide 可以在祖先組件中指定我們想要提供給后代組件的數據或方法,而在任何后代組件中,我們都可以使用 inject 來接收 provide 提供的數據或方法。
父組件
子/孫組件
<script lang="ts" setup> //子孫組件引入inject import { ref,inject } from "vue";const reload = inject("reload");//調用方法使用 const handleClick = (val: any) => {if (typeof reload == "function") reload(); }; </script >希望能幫助到大家,同時祝愿大家在開發旅途中愉快!!!
拿著 不謝 請叫我“錘” !!!
可以運用nvm管理node多版本,其中最常見就是環境依賴問題 (npm 安裝報錯 npm ERR! Unexpected token ‘.’) 可以參考這篇文章:https://www.cnblogs.com/yilei-zero/p/16003054.html ??
總結
- 上一篇: CentOS7.X安装部署Glassfi
- 下一篇: c语言的整型常量分为,C语言中整型常量和