【vue3】项目搭建

简介

vue3:双向绑定改为ES6的Proxy;新的API风格,代码逻辑性更强、更易维护;性能提升,渲染更快、内存更少。
vite:新型前端构建工具,基于原生ES模块,极速启动、快速热更新,更优的开发体验。

以npm install和build过程为例, 之前vue2+webpack的项目在devops的编译环节非常耗时,在2-15min之间均有,vue3+vite的项目基本在1min以内。

脚手架

事先准备
nodejs需要大于16.0版本。
建议先卸载旧有nodejs,再安装nvm,通过nvm安装分别用于vue3项目和vue2项目的nodejs高低版本。

  1. 创建指令:npm create vue@latest
  2. 选项:TypeScript、Vue Router、ESLint 、Prettier (按需即可)
  3. 运行指令:
      npm install
      npm run dev
    

引入axios

  1. npm install axios --save
  2. 配置文件axios-config.js,统一封装请求
    /request/axios-config.js
    import axios from "axios";
    import router from "@/router";
    import qs from "qs";
    
    /* http request
     **请求拦截器
     **在发送请求之前进行的一系列处理,根据项目要求自行配置
     **例如:loading
     */
    axios.interceptors.request.use(
      (config) => {
        // 请求响应时间
        config.timeout = 60 * 60 * 1000;
        config.headers = {
          token: sessionStorage.getItem("accessToken"),
          // "Content-Type": "application/json"
          "Content-Type": "application/x-www-form-urlencoded",
        };
        return config;
      },
      (error) => {
        // 对请求错误做处理
        console.log(error); // for debug
        return Promise.reject(error);
      }
    );
    
    /* response
     **响应拦截器
     **允许在数据返回客户端前,修改响应的数据
     **返回体中数据:response.data,如果需要全部,则 return response 即可
     */
    axios.interceptors.response.use(
      (response) => response,
      (error) => {
        let message = "";
        // 处理响应错误
        if (error && error.response) {
          const errorResponse = error.response.data;
          if (errorResponse.msg || errorResponse.message) {
            message = errorResponse.msg || errorResponse.message;
            if (message.indexOf("无效token") > -1) {
              sessionStorage.removeItem("accessToken");
              sessionStorage.removeItem("userinfo");
              router.push({ path: "/login" });
            }
          }
        }
        return Promise.reject(error);
      }
    );
    
    const fetchPost = (url, params) => {
      return new Promise((resolve, reject) => {
        axios
          .post(url, qs.stringify(params))
          .then(
            (res) => {
              resolve(res.data.data);
            },
            (err) => {
              reject(err.data);
            }
          )
          .catch((err) => {
            reject(err.data);
          });
      });
    };
    
    const fetchPut = (url, params) => {
      return new Promise((resolve, reject) => {
        axios
          .put(url, qs.stringify(params))
          .then((res) => {
            resolve(res.data.data);
          })
          .catch((err) => {
            reject(err.data);
          });
      });
    };
    
    const fetchDel = (url, params) => {
      return new Promise((resolve, reject) => {
        axios
          .delete(url, {
            params: qs.stringify(params),
          })
          .then((res) => {
            resolve(res.data.data);
          })
          .catch((err) => {
            reject(err.data);
          });
      });
    };
    const fetchGet = (url, params) => {
      return new Promise((resolve, reject) => {
        axios
          .get(url, {
            params: qs.stringify(params),
          })
          .then((res) => {
            resolve(res.data.data);
          })
          .catch((err) => {
            reject(err.data);
          });
      });
    };
    
    /**
     * 不带参数的get请求
     * @param {*} url
     */
    const fetchGetNoParam = (url) => {
      return new Promise((resolve, reject) => {
        axios
          .get(url)
          .then((res) => {
            resolve(res.data.data);
          })
          .catch((err) => {
            reject(err.data);
          });
      });
    };
    
    export default {
      install: (app) => {
        app.config.globalProperties["$get"] = fetchGet;
        app.config.globalProperties["$post"] = fetchPost;
        app.config.globalProperties["$put"] = fetchPut;
        app.config.globalProperties["$del"] = fetchDel;
        app.config.globalProperties["$axios"] = axios;
      },
    };
    
  3. main.js引入
    import Axios from "@/request/axios-config.js";
    const app = createApp(App)
      .use(Axios);
    
  4. .vue使用
    import { getCurrentInstance } from "vue";
    const { proxy } = getCurrentInstance();
    
    let data=await proxy.$post("url",{});
    

引入sass

  1. npm install sass --save -dev
  2. npm install sass-loader --save -dev
  3. .vue使用:<style scoped lang="scss"></style>

引入element-plus

  1. npm install element-plus --save
  2. main.js引入
    import "element-plus/dist/index.css";
    import ElementPlus from "element-plus";
    import zhCn from "element-plus/dist/locale/zh-cn.mjs";
    
    const app = createApp(App)
      .use(ElementPlus, {
        locale: zhCn,
      });
    
  3. 使用见官网

vite.config.js

"@"路径配置及代理配置

import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
  server: {
    port: 8081,
    https: false,
    proxy: {
      "/check": {
        // 后台地址
        target: "http://127.0.0.1:18892",
        changeOrigin: true,
        // pathRewrite: {
        //   "^/check": "",
        // },
      },
    },
  },
});

引入echarts5

  1. npm install echarts --save
  2. .vue使用
    import * as echarts from "echarts";
    
    let myChart = null; //用const和ref()会导致tooltip提示不显示
    myChart = echarts.init(document.getElementById(id));
    let option = {};
    myChart.setOption(option);
    window.addEventListener("resize", () => {
      myChart.resize();
    });
    

路由配置

/router/index.js

import { createRouter, createWebHistory } from "vue-router";

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: "/login",
      name: "login",
      component: () => import("../views/LoginView.vue"),
    },
    {
      path: "/",
      name: "home",
      component: () => import("../views/HomeView.vue"),
      children: [
        {
          path: "/index",
          name: "index",
          component: () => import("../views/Index.vue"),
        },
        
      ],
    },
  ],
});

router.beforeEach((to, from) => {
  if (!sessionStorage.getItem("accessToken") && to.name !== "login") {
    return { path: "/login" };
  }
  return true;
});

export default router;

main.js引入

import router from "./router";
const app = createApp(App)
  .use(router);

全局状态管理

/store/store.js

import { reactive } from "vue";

export const store = reactive({
  count: 0func: () => {
    ...
  },
});

.vue使用

<template> {{ store.count }}</template>

<script setup>
import { store } from './store.js'

store.func();
</script>

完整main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";

import "./assets/main.css";

import "element-plus/dist/index.css";
import ElementPlus from "element-plus";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";

import Axios from "@/request/axios-config.js";

const app = createApp(App)
  .use(router)
  .use(ElementPlus, {
    locale: zhCn,
  })
  .use(Axios);

app.mount("#app");

组合式API之Setup

常用功能

<script lang="ts" setup>
import { reactive, ref, getCurrentInstance, computed, onMounted } from "vue";
import { useRouter, useRoute, RouterView } from "vue-router";
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
import { store } from "@/store/store.js";

// 计算属性,获取当前路由名称
const current= computed(() => {
  return route.name;
});

// 钩子函数
// 在组件完成初始渲染并创建 DOM 节点后运行
onMounted(() => {
  init();
});

// 响应式变量声明
const showTable = ref(false);
let tableData = reactive([]); 

// axios请求及store状态管理
const init= () => {
  tableData = await proxy.$post("/getResultList", {
    quarter: store.getQuarter(),
    year: store.getYear(),
  });
  showTable.value = true
};

// 路由跳转
const goLogin= () => {
  router.push({ path: "/login" });
};
  • ref:可以是 string、number 或 boolean 这样的原始类型,也可以是对象类型;在js中需要通过 .value,在template不需要;适合于原始类型和浅层级的对象。
  • reactive:只能用于对象类型;不需要 .value;适合于层级比较深的可变复杂对象。

父子组件传值

父组件

<Chart
  v-if="chartShow['v4']"
  id="v4"
  :tip="tip['v4']"
  :title="titles['v4']"
  :legend="legend['v4']"
  :chartData="chartData['v4']"
  :isPercent="isPercent['v4']"
></Chart>

import Chart from "../components/Chart.vue";

子组件

<template>
  <div class="box">
    <div v-if="title" class="box_top">
      <div class="title">{{ title }}</div>
    </div>
    <div class="box_chart" ref="chart" :id="id"></div>
  </div>
</template>

<script lang="ts" setup>
import { defineProps, onMounted, watch } from "vue";

//父传子
const props = defineProps({
  id: {
    type: String,
    required: true,
  },
  isPercent: {
    type: Boolean,
    default: () => true,
  },
  title: {
    type: String,
    required: false,
  },
  chartData: {
    type: Array,
    default: () => [],
  },
});

const emits = defineEmits(["updateData", "updateThreshold"]);

//监听数组变化
watch(
  () => props.chartData,
  () => {
    init();
  }
);
onMounted(() => {
  init();
});

let myChart = null;
const init = () => {
  //获取传值
  console.log((props.id);
};
const handelChange= () => {
  //子传父
  emits("updateData", [props.id,val1,val2,...]);
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值