企业管理系统定制开发vue3的那些事

企业管理系统定制开发没有特别的幸运,企业管理系统定制开发那么就特别的努力!!!

vue3 + + ts + vant + axios + sass 移动端h5企业管理系统定制开发搭建新项目

vue3 + vite + ts + vant + axios + sass

企业管理系统定制开发搭建第一个 Vite 项目 (vite + vue + ts)

企业管理系统定制开发兼容性注意
Vite 需要 Node.js 版本 14.18+,16+。然而,企业管理系统定制开发有些模板需要依赖更高的 Node 企业管理系统定制开发版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。

nvm管理node多版本。

// 搭建第一个 Vite 项目 (vite + vue + ts)// npm (本篇采用npm搭建)npm init vite@latest // yarnyarn create vite// pnpmpnpm create vite
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
# npm 6.xnpm create vite@latest vite-vue3 --template vue# npm 7+, extra double-dash is needed:npm create vite@latest vite-vue3 -- --template vue# yarnyarn create vite vite-vue3 --template vue# pnpmpnpm create vite vite-vue3 --template vue
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

项目启动

cd vite-vue3npm installnpm run dev
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

代码规范 (格式化、提示)

eslint

# 自动生成配置文件并安装下面四个依赖npx eslint --init# 或者手动创建文件# npm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue -D
  • 1
  • 2
  • 3
  • 4
  • 5

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

创建prettier文件

// prettier.cjsmodule.exports = {  printWidth: 100,  tabWidth: 2,  useTabs: false, // 是否使用tab进行缩进,默认为false  singleQuote: true, // 是否使用单引号代替双引号,默认为false  semi: true, // 行尾是否使用分号,默认为true  arrowParens: 'always',  endOfLine: 'auto',  vueIndentScriptAndStyle: true,  htmlWhitespaceSensitivity: 'strict',};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

配置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',  },};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

配置 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" }]}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

tsconfig.node.json

{  "compilerOptions": {    "composite": true,    "module": "ESNext",    "moduleResolution": "Node",    "allowSyntheticDefaultImports": true  },  "include": ["vite.config.ts", "config/index.ts"]}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

CSS 预处理器

less安装使用

// npm 安装npm install lessnpm install less-loader// yarn 安装yarn add less less-loader
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
// 使用< style lang="less" scoped></ style>
  • 1
  • 2

sass安装使用

// npm 安装npm install -D sass sass-loader// yarn 安装yarn add sass sass-loader
  • 1
  • 2
  • 3
  • 4
  • 5
<style lang="scss" scoped>.home {  background-color: #eee;  height: 100vh;}</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

vant 安装


安装

// npm 安装npm i vant// yarn 安装yarn add vant// 通过 pnpm 安装pnpm add vant
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

常规用法

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');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

按需引入组件样式

// 通过 npm 安装npm i unplugin-vue-components -D// 通过 yarn 安装yarn add unplugin-vue-components -D// 通过 pnpm 安装pnpm add unplugin-vue-components -D
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

配置插件
vite 的项目,在 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()],    }),  ],};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

使用组件

<template>  <van-button type="primary" /></template>
  • 1
  • 2
  • 3

Rem 布局适配

// npm 安装npm install -D postcss-pxtorem lib-flexible// yarn 安装yarn add postcss-pxtorem lib-flexible
  • 1
  • 2
  • 3
  • 4
  • 5

根目录下面新建一个 .config.js 文件

// postcss.config.jsmodule.exports = {  plugins: {    'postcss-pxtorem': {      rootValue: 37.5,      propList: ['*'],    },  },};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

底部适配 - 对于ios系统

<!-- 在 head 标签中添加 meta 标签,并设置 viewport-fit=cover 值 --><meta  name="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 />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

vue-router

1.安装

npm i vue-router@4
  • 1

2.创建路由

// 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
// 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: '首页'    }  },];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3.挂载路由

// src/main.tsimport { 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');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.使用

<template>  <router-view /></template>
  • 1
  • 2
  • 3

Axios

1.安装

// npm 安装npm i axios// yarn 安装yarn add axios
  • 1
  • 2
  • 3
  • 4
  • 5
// 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设置不同的baseURL  baseURL: 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
// 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
// src/utils/http/types.ts// 和后端约定好接口返回的数据结构export interface Response<T = any> {  data: string[];  code: number | string;  message: string;  result: T;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

示例页面

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.name  getColumnResourceList()})const getColumnResourceList = () => monthlyResourceList(params.value).then(res => {  loading.value = true  if (res.success) {    loading.value = false    list.value = [...list.value,...res.data]    // 如果列表数据条数>=总条数,不再触发滚动加载    if (list.value.length >= res.totalCount) {      finished.value = true    }  }})const onRefresh = () => {  params.value.currentPage = 1  finished.value = false;  refreshing.value = false  list.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-list      v-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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

项目地址

为了安全协议:项目地址api 已全部替换(望理解!!!)




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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

子组件

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

withDefaults 定义默认值

<script setup lang="ts">import { defineProps } from "vue";withDefaults(  defineProps<{ msg?: (string | number | boolean), title?: string }>(),{      msg:'hello vite',      title:'默认标题'  });</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

父组件接收

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

ref VS reactive

  1. reactive返回一个对象的响应式代理。
  2. ref参数一般接收简单数据类型,若ref接收对象为参数,本质上会转变为reactive方法
  3. 在JS中访问ref的值需要手动添加.value,访问reactive不需要
  4. 响应式的底层原理都是Proxy

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

监听多个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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

监听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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

provide/inject

provide 可以在祖先组件中指定我们想要提供给后代组件的数据或方法,而在任何后代组件中,我们都可以使用 inject 来接收 provide 提供的数据或方法。
父组件

<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进行注册provide('reload', reload);</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

子/孙组件

<script lang="ts" setup>//子孙组件引入injectimport { ref,inject } from "vue";const reload = inject("reload");//调用方法使用const handleClick = (val: any) => {   if (typeof reload == "function") reload();};</script >
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

希望能帮助到大家,同时祝愿大家在开发旅途中愉快!!!


  1. 可以运用nvm管理node多版本,其中最常见就是环境依赖问题 (npm 安装报错 npm ERR! Unexpected token ‘.’) 可以参考这篇文章:

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发