一 、通過雲開發平臺快速創建初始化應用 1.創建相關應用模版請參考鏈接:去中心化的前端構建工具 — Vite 2.完成創建後就可以在github中查看到新增的Vite倉庫 二 、 本地編寫 Vite後臺項目最佳起始點 1.將應用模版克隆到本地 首先假定你已經安裝了Git、node,沒有安裝請移步no ...
一 、通過雲開發平臺快速創建初始化應用
1.創建相關應用模版請參考鏈接:去中心化的前端構建工具 — Vite
2.完成創建後就可以在github中查看到新增的Vite倉庫
二 、 本地編寫 Vite後臺項目最佳起始點
1.將應用模版克隆到本地
- 首先假定你已經安裝了Git、node,沒有安裝請移步node官網進行安裝。克隆項目:
git clone + 項目地址
- 進入項目文件
cd Vite
- 切換到feature/1.0.0 分支上
git checkout feature/1.0.0
- 安裝依賴包
npm install
- 啟動服務
npm run dev
這裡打開瀏覽器3000埠,並出現預設頁面。
2.路由
- 安裝 vue-router 4.x
npm i vue-router@next -S
- 路由配置 router/index.js
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/', component: () => import('views/home.vue') }
]
});
export default router
- 引入 main.js
import router from "@/router";
createApp(App).use(router).mount("#app");
3.狀態管理
- 安裝 vuex 4.x
npm i vuex@next -S
- Store配置 store/index.js
import {createStore} from 'vuex';
export default createStore({
state: {
couter: 0
}
});
- 引入 main.js
import store from "@/store";
createApp(App).use(store).mount("#app");
4.樣式組織
- 安裝 sass
npm i sass -D
styles 目錄保存各種樣式
index.scss 作為出口組織這些樣式,同時編寫一些全局樣式
最後在main.js導入
5.UI庫
- 安裝
npm i element3 -S
- 完整引入 main.js
import element3 from "element3";
import "element3/lib/theme-chalk/index.css";
createApp(App).use(element3)
- 按需引入 main.js
import "element3/lib/theme-chalk/button.css";
import { ElButton } from "element3"
createApp(App).use(ElButton)
抽取成插件會更好 plugins/element3.js
// 完整引入
import element3 from "element3";
import "element3/lib/theme-chalk/index.css";
// 按需引入
// import { ElButton } from "element3";
// import "element3/lib/theme-chalk/button.css";
export default function (app) {
// 完整引入
app.use(element3)
// 按需引入
// app.use(ElButton);
}
- 測試
<el-button>my button</el-button>
6.基礎佈局
我們應用需要一個基本佈局頁,類似下圖,將來每個頁面以佈局頁為父頁面即可:
- 佈局頁面 layout/index.vue
<template>
<div class="app-wrapper">
<!-- 側邊欄 -->
<div class="sidebar-container"></div>
<!-- 內容容器 -->
<div class="main-container">
<!-- 頂部導航欄 -->
<navbar />
<!-- 內容區 -->
<app-main />
</div>
</div>
</template>
<script setup>
import AppMain from "./components/AppMain.vue";
import Navbar from "./components/Navbar.vue";
</script>
<style lang="scss" scoped>
@import "../styles/mixin.scss";
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
}
</style>
- 路由配置 router/index.js
{
path: "/",
component: Layout,
children: [
{
path: "",
component: () => import('views/home.vue'),
name: "Home",
meta: { title: "首頁", icon: "el-icon-s-home" },
},
],
},
7.動態導航
- 側邊導航
根據路由表動態生成側邊導航菜單。
首先創建側邊欄組件,遞歸輸出routes中的配置為多級菜單,layout/Sidebar/index.vue
<template>
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
mode="vertical"
>
<sidebar-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</el-scrollbar>
</template>
<script setup>
import SidebarItem from "./SidebarItem.vue";
import { computed } from "vue";
import { useRoute } from "vue-router";
import { routes } from "@/router";
import variables from "styles/variables.module.scss";
const activeMenu = computed(() => {
const route = useRoute();
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
});
</script>
- 添加相關樣式:
○ styles/variables.module.scss
○ styles/sidebar.scss
○ styles/index.scss中引入
創建SidebarItem.vue組件,解析當前路由是導航鏈接還是父菜單:
8.麵包屑
通過路由匹配數組可以動態生成麵包屑。
麵包屑組件,layouts/components/Breadcrumb.vue
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span
v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
class="no-redirect"
>{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup>
import { compile } from "path-to-regexp";
import { reactive, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
const levelList = ref(null);
const router = useRouter();
const route = useRoute();
const getBreadcrumb = () => {
let matched = route.matched.filter((item) => item.meta && item.meta.title);
const first = matched[0];
if (first.path !== "/") {
matched = [{ path: "/home", meta: { title: "首頁" } }].concat(matched);
}
levelList.value = matched.filter(
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
);
}
const pathCompile = (path) => {
var toPath = compile(path);
return toPath(route.params);
}
const handleLink = (item) => {
const { redirect, path } = item;
if (redirect) {
router.push(redirect);
return;
}
router.push(pathCompile(path));
}
getBreadcrumb();
watch(route, getBreadcrumb)
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>
9.數據封裝
統一封裝數據請求服務,有利於解決一下問題:
- 統一配置請求
- 請求、響應統一處理
準備工作:
- 安裝axios:
npm i axios -S
添加配置文件:.env.development
VITE_BASE_API=/api
請求封裝 utils/request.js
import axios from "axios";
import { Message, Msgbox } from "element3";
// 創建axios實例
const service = axios.create({
// 在請求地址前面加上baseURL
baseURL: import.meta.env.VITE_BASE_API,
// 當發送跨域請求時攜帶cookie
// withCredentials: true,
timeout: 5000,
});
// 請求攔截
service.interceptors.request.use(
(config) => {
// 模擬指定請求令牌
config.headers["X-Token"] = "my token";
return config;
},
(error) => {
// 請求錯誤的統一處理
console.log(error); // for debug
return Promise.reject(error);
}
);
// 響應攔截器
service.interceptors.response.use(
/**
* 通過判斷狀態碼統一處理響應,根據情況修改
* 同時也可以通過HTTP狀態碼判斷請求結果
*/
(response) => {
const res = response.data;
// 如果狀態碼不是20000則認為有錯誤
if (res.code !== 20000) {
Message.error({
message: res.message || "Error",
duration: 5 * 1000,
});
// 50008: 非法令牌; 50012: 其他客戶端已登入; 50014: 令牌過期;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// 重新登錄
Msgbox.confirm("您已登出, 請重新登錄", "確認", {
confirmButtonText: "重新登錄",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
store.dispatch("user/resetToken").then(() => {
location.reload();
});
});
}
return Promise.reject(new Error(res.message || "Error"));
} else {
return res;
}
},
(error) => {
console.log("err" + error); // for debug
Message({
message: error.message,
type: "error",
duration: 5 * 1000,
});
return Promise.reject(error);
}
);
export default service;
10.常見業務處理
- 結構化數據展
使用el-table展示結構化數據,配合el-pagination做數據分頁。
文件組織結構如下:list.vue展示列表,edit.vue和create.vue編輯或創建,內部復用detail.vue處理,model中負責數據業務處理。
list.vue中的數據展示
<el-table v-loading="loading" :data="list">
<el-table-column label="ID" prop="id"></el-table-column>
<el-table-column label="賬戶名" prop="name"></el-table-column>
<el-table-column label="年齡" prop="age"></el-table-column>
</el-table>
list和loading數據的獲取邏輯,可以使用compsition-api提取到userModel.js
export function useList() {
// 列表數據
const state = reactive({
loading: true, // 載入狀態
list: [], // 列表數據
});
// 獲取列表
function getList() {
state.loading = true;
return request({
url: "/getUsers",
method: "get",
}).then(({ data, total }) => {
// 設置列表數據
state.list = data;
}).finally(() => {
state.loading = false;
});
}
// 首次獲取數據
getList();
return { state, getList };
}
list.vue中使用
import { useList } from "./model/userModel";
const { state, getList } = useList();
分頁處理 list.vue
<pagination
:total="total"
v-model:page="listQuery.page"
v-model:limit="listQuery.limit"
@pagination="getList"
></pagination>
數據也在userModel中處理
const state = reactive({
total: 0, // 總條數
listQuery: {// 分頁查詢參數
page: 1, // 當前頁碼
limit: 5, // 每頁條數
},
});
request({
url: "/getUsers",
method: "get",
params: state.listQuery, // 在查詢中加入分頁參數
})
11.表單處理
用戶數據新增、編輯使用el-form處理
可用一個組件detail.vue來處理,區別僅在於初始化時是否獲取信息回填到表單。
<el-form ref="form" :model="model" :rules="rules">
<el-form-item prop="name" label="用戶名">
<el-input v-model="model.name"></el-input>
</el-form-item>
<el-form-item prop="age" label="用戶年齡">
<el-input v-model.number="model.age"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="submitForm" type="primary">提交</el-button>
</el-form-item>
</el-form>
數據處理同樣可以提取到userModel中處理。
export function useItem(isEdit, id) {
const model = ref(Object.assign({}, defaultData));
// 初始化時,根據isEdit判定是否需要獲取詳情
onMounted(() => {
if (isEdit && id) {
// 獲取詳情
request({
url: "/getUser",
method: "get",
params: { id },
}).then(({ data }) => {
model.value = data;
});
}
});
return { model };
}
三 、 雲端一鍵部署上線應用
1.上傳代碼
git add .
git commit -m '添加你的註釋'
git push
2.在日常環境部署
一鍵進行應用部署。在應用詳情頁面點擊日常環境的「部署」按鈕進行一鍵部署,部署狀態變成綠色已部署以後可以點擊訪問部署網站查看效果。
3.配置自定義功能變數名稱線上上環境上線
- 配置線上環境自定義功能變數名稱。在功能開發驗證完成後要線上上環境進行部署,線上上環境的「部署配置」-「自定義功能變數名稱」中填寫自己的功能變數名稱。例如我們添加一個二級功能變數名稱 company.workbench.fun 來綁定我們部署的前端應用。然後複製自定義功能變數名稱下方的API網關地址對添加的二級功能變數名稱進行CNAME配置。
- 配置CNAME地址。複製好 API網關功能變數名稱地址後,來到你自己的功能變數名稱管理平臺(此示例中的功能變數名稱管理是阿裡雲的功能變數名稱管理控制台,請去自己的功能變數名稱控制台操作)。添加記錄的「記錄類型」選擇「CNAME」,在「主機記錄」中輸入你要創建的二級功能變數名稱,這裡我們輸入「company」,在「記錄值」中粘貼我們之前複製的 API網關功能變數名稱地址,「TTL」保留預設值或者設置一個你認為合適的值即可。
- 線上上環境部署上線。回到雲開發平臺的應用詳情頁面,按照部署的操作,點擊線上環境的「部署按鈕」,部署完成以後就在你自定義的功能變數名稱進行了上線。CNAME 生效之後,我們輸入 company.workbench.fun(示例網址) 可以打開部署的頁面。至此,如何部署一個應用到線上環境,如何綁定自己的功能變數名稱來訪問一個線上的應用就完成了,趕緊部署自己的應用到線上環境,用自己的功能變數名稱玩起來吧 ;)
4.項目預覽效果
一鍵創建Vite應用模版鏈接 :https://workbench.aliyun.com/application/front/create?fromConfig=27&fromRepo=sol_github_27
參考文獻:https://juejin.cn/post/6926822933721513998#heading-22