日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > vue >内容正文

vue

vue3的那些事

發(fā)布時(shí)間:2023/12/18 vue 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vue3的那些事 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

沒有特別的幸運(yùn),那么就特別的努力!!!

vue3 + vite + ts + vant + axios + sass 移動(dòng)端h5搭建新項(xiàng)目

  • vue3 + vite + ts + vant + axios + sass
    • 搭建第一個(gè) Vite 項(xiàng)目 (vite + vue + ts)
      • nvm管理node多版本。[^1]
    • 代碼規(guī)范 (格式化、提示)
      • eslint
      • prettier
      • 配置eslintrc
    • 配置 tsconfig
    • CSS 預(yù)處理器
      • less安裝使用
      • sass安裝使用
    • vant 安裝
      • Rem 布局適配
      • 底部適配 - 對(duì)于ios系統(tǒng)
    • vue-router
    • Axios
      • 示例頁(yè)面
    • 項(xiàng)目地址
  • vue3 開發(fā)
    • 父組件傳參
      • defineProps
      • withDefaults 定義默認(rèn)值
      • defineEmits
    • ref VS reactive
    • watch
      • 監(jiān)聽ref定義的一個(gè)響應(yīng)式數(shù)據(jù)
      • 監(jiān)聽多個(gè)ref
      • 監(jiān)聽reactive 定義響應(yīng)式對(duì)象的單一屬性
      • watch VS watchEffect
    • 生命周期
    • keep-alive 緩存組件
    • provide/inject

vue3 + vite + ts + vant + axios + sass

vite官網(wǎng):

搭建第一個(gè) Vite 項(xiàng)目 (vite + vue + ts)

兼容性注意
Vite 需要 Node.js 版本 14.18+,16+。然而,有些模板需要依賴更高的 Node 版本才能正常運(yùn)行,當(dāng)你的包管理器發(fā)出警告時(shí),請(qǐng)注意升級(jí)你的 Node 版本。

nvm管理node多版本。1

// 搭建第一個(gè) Vite 項(xiàng)目 (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

項(xiàng)目啟動(dòng)

cd vite-vue3npm install npm run dev

代碼規(guī)范 (格式化、提示)

eslint

# 自動(dòng)生成配置文件并安裝下面四個(gè)依賴 npx eslint --init# 或者手動(dòng)創(chuàng)建文件 # npm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue -D

prettier

npm i prettier eslint-config-prettier eslint-plugin-prettier -D

創(chuàng)建prettier文件

// prettier.cjsmodule.exports = {printWidth: 100,tabWidth: 2,useTabs: false, // 是否使用tab進(jìn)行縮進(jìn),默認(rèn)為falsesingleQuote: true, // 是否使用單引號(hào)代替雙引號(hào),默認(rèn)為falsesemi: true, // 行尾是否使用分號(hào),默認(rèn)為truearrowParens: 'always',endOfLine: 'auto',vueIndentScriptAndStyle: true,htmlWhitespaceSensitivity: 'strict', };

配置eslintrc

// eslintrc.cjsmodule.exports = {root: true, // 停止向上查找父級(jí)目錄中的配置文件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', // 指定要使用的解析器// 給解析器傳入一些其他的配置參數(shù)parserOptions: {ecmaVersion: 'latest', // 支持的es版本parser: '@typescript-eslint/parser',sourceType: 'module', // 模塊類型,默認(rèn)為script,我們?cè)O(shè)置為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,// 👆是初始化默認(rèn)配置/*在ts中導(dǎo)入js模塊會(huì)報(bào)錯(cuò)找不到類型聲明解決方法一:僅設(shè)置 "allowJs": true 即可注:allowJs設(shè)置true時(shí),下方include不可以加入'src/**\/*.js',否則報(bào)錯(cuò)'無(wú)法寫入文件xx因?yàn)樗鼤?huì)覆蓋輸入文件'方法二:僅在 env.d.ts 中加入 declare module '*.js'; 模塊定義即可總結(jié):和 "include": ["src/**\/*.js"] 沒有任何關(guān)系*/"allowJs": true, // 允許編譯器編譯JS,JSX文件"baseUrl": "./",// "typeRoots": [// "node_modules/@types" // 默認(rèn)會(huì)從'node_modules/@types'路徑去引入聲明文件// ],// "types": ["node"] // 僅引入'node'模塊// "paths"是相對(duì)于"baseUrl"進(jìn)行解析// 在vite.config里配置了路徑別名resolve.alias,為了讓編譯 ts 時(shí)也能夠解析對(duì)應(yīng)的路徑,我們還需要配置 paths 選項(xiàng)"paths": {"@/*": ["src/*"],}},"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],// references屬性是 TypeScript 3.0 的新特性,允許將 TypeScript 程序拆分結(jié)構(gòu)化(即拆成多個(gè)文件,分別配置不同的部分)。"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 預(yù)處理器

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官網(wǎng)地址:
安裝

// npm 安裝 npm i vant// yarn 安裝 yarn add vant// 通過(guò) pnpm 安裝 pnpm add vant

常規(guī)用法

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. 注冊(cè)你需要的組件 app.use(Button);app.mount('#app');

按需引入組件樣式

// 通過(guò) npm 安裝 npm i unplugin-vue-components -D// 通過(guò) yarn 安裝 yarn add unplugin-vue-components -D// 通過(guò) pnpm 安裝 pnpm add unplugin-vue-components -D

配置插件
vite 的項(xiàng)目,在 vite.config.js 文件中配置插件:

import vue from '@vitejs/plugin-vue'; import Components from 'unplugin-vue-components/vite'; import { VantResolver } from 'unplugin-vue-components/resolvers';export default {plugins: [vue(),Components({resolvers: [VantResolver()],}),], };

使用組件

<template><van-button type="primary" /> </template>

Rem 布局適配

// npm 安裝 npm install -D postcss-pxtorem lib-flexible// yarn 安裝 yarn add postcss-pxtorem lib-flexible

根目錄下面新建一個(gè) postcss.config.js 文件

// postcss.config.js module.exports = {plugins: {'postcss-pxtorem': {rootValue: 37.5,propList: ['*'],},}, };

底部適配 - 對(duì)于ios系統(tǒng)

<!-- 在 head 標(biāo)簽中添加 meta 標(biāo)簽,并設(shè)置 viewport-fit=cover 值 --> <metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" /><!-- 開啟頂部安全區(qū)適配 --> <van-nav-bar safe-area-inset-top /><!-- 開啟底部安全區(qū)適配 --> <van-number-keyboard safe-area-inset-bottom />

vue-router

1.安裝

npm i vue-router@4

2.創(chuàng)建路由

// src/router/index.ts//現(xiàn)在創(chuàng)建router的方式與vue2.x的版本已經(jīng)很不同了 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: '首頁(yè)'}},];

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';// 創(chuàng)建axios實(shí)例 const service = axios.create({// 根據(jù)不同env設(shè)置不同的baseURLbaseURL: import.meta.env.VITE_APP_API_BASE_URL, });// axios實(shí)例攔截請(qǐng)求 service.interceptors.request.use((config: AxiosRequestConfig) => {config.headers = {...config.headers,// ...auth.headers(), // 你的自定義headers,如token等};return config;},(error: AxiosError) => {return Promise.reject(error);} );// axios實(shí)例攔截響應(yīng) service.interceptors.response.use(// 2xx時(shí)觸發(fā)(response: AxiosResponse<Response>) => {// response.data就是后端返回的數(shù)據(jù),結(jié)構(gòu)根據(jù)你們的約定來(lái)定義const { code, message } = response.data;let errMessage = '';switch (code) {case 0:break;case 1: // token過(guò)期errMessage = 'Token expired';router.push('/login');break;case 2: // 無(wú)權(quán)限errMessage = 'No permission';break;// default:// errMessage = message;// break;}if (errMessage) Toast.fail(errMessage);return response;},// 非2xx時(shí)觸發(fā)(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) => {// 一些業(yè)務(wù)處理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// 和后端約定好接口返回的數(shù)據(jù)結(jié)構(gòu) export interface Response<T = any> {data: string[];code: number | string;message: string;result: T; }

示例頁(yè)面

banner列表頁(yè)面

<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]// 如果列表數(shù)據(jù)條數(shù)>=總條數(shù),不再觸發(fā)滾動(dòng)加載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>

項(xiàng)目地址

為了安全協(xié)議:項(xiàng)目地址api 已全部替換(望理解!!!)
https://gitee.com/hammer1010_admin/vue3-vite




vue3 開發(fā)

父組件傳參

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 定義默認(rèn)值

<script setup lang="ts"> import { defineProps } from "vue"; withDefaults(defineProps<{ msg?: (string | number | boolean), title?: string }>(),{msg:'hello vite',title:'默認(rèn)標(biāo)題'} );</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

  • reactive返回一個(gè)對(duì)象的響應(yīng)式代理。
  • ref參數(shù)一般接收簡(jiǎn)單數(shù)據(jù)類型,若ref接收對(duì)象為參數(shù),本質(zhì)上會(huì)轉(zhuǎn)變?yōu)閞eactive方法
  • 在JS中訪問(wèn)ref的值需要手動(dòng)添加.value,訪問(wèn)reactive不需要
  • 響應(yīng)式的底層原理都是Proxy
  • watch

    偵聽一個(gè)或多個(gè)響應(yīng)式數(shù)據(jù)源,并在數(shù)據(jù)源變化時(shí)調(diào)用所給的回調(diào)函數(shù)。

    監(jiān)聽ref定義的一個(gè)響應(yīng)式數(shù)據(jù)

    <script setup lang="ts"> import { ref, watch } from "vue";const str = ref('一個(gè)值')//3s后改變str的值 setTimeout(() => { str.value = '3s后一個(gè)值' }, 3000)watch(str, (newV, oldV) => {console.log(newV, oldV) //3s后一個(gè)值 一個(gè)值 })</script>

    監(jiān)聽多個(gè)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>

    監(jiān)聽reactive 定義響應(yīng)式對(duì)象的單一屬性

    <script setup lang="ts"> import { reactive, watch } from "vue";let info = reactive({name: '張麻子',age: 18,obj: {str: '彼時(shí)彼刻,恰如此時(shí)此刻'} })//3s后改變s值 setTimeout(() => {info.obj.str = 'to be or not to be' }, 3000)// 需要自己開啟 deep:true深度監(jiān)聽,不然不發(fā)觸發(fā) watch 的回調(diào)函數(shù) watch(() => info.obj, (newV, oldV) => {console.log(newV, oldV) }, {deep: true })</script>

    watch VS watchEffect

    watch只有監(jiān)聽的值發(fā)生變化的時(shí)候才會(huì)執(zhí)行
    watchEffect 立即運(yùn)行一個(gè)函數(shù),同時(shí)響應(yīng)式地追蹤其依賴,并在依賴更改時(shí)重新執(zhí)行。
    wacthEffect 無(wú)法獲取到原值,只能得到變化后的值
    watchEffect 不用指明監(jiān)視哪個(gè)屬性,監(jiān)視的回調(diào)中用到哪個(gè)屬性就監(jiān)視哪個(gè)屬性

    生命周期

    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 可以在祖先組件中指定我們想要提供給后代組件的數(shù)據(jù)或方法,而在任何后代組件中,我們都可以使用 inject 來(lái)接收 provide 提供的數(shù)據(jù)或方法。
    父組件

    <template><router-view v-if="isRouterView"></router-view> </template><script lang="ts" setup> import { ref, provide, nextTick } from "vue"; const isRouterView = ref(true); //父組件刷新方法 const reload = () => {isRouterView.value = false;nextTick(() => {isRouterView.value = true;}) } //provide進(jìn)行注冊(cè) provide('reload', reload); </script>

    子/孫組件

    <script lang="ts" setup> //子孫組件引入inject import { ref,inject } from "vue";const reload = inject("reload");//調(diào)用方法使用 const handleClick = (val: any) => {if (typeof reload == "function") reload(); }; </script >

    希望能幫助到大家,同時(shí)祝愿大家在開發(fā)旅途中愉快!!!

    拿著 不謝 請(qǐng)叫我“錘” !!!


  • 可以運(yùn)用nvm管理node多版本,其中最常見就是環(huán)境依賴問(wèn)題 (npm 安裝報(bào)錯(cuò) npm ERR! Unexpected token ‘.’) 可以參考這篇文章:https://www.cnblogs.com/yilei-zero/p/16003054.html ??

  • 總結(jié)

    以上是生活随笔為你收集整理的vue3的那些事的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。