テンセントのアーキテクトに連れられてコードを書く - vue real enterprise practice sharing
2022-02-22 18:58:27
Vue.js+element uiによるバックエンド管理システムの構築
この記事を読むと何が得られるのか?
- とぼけることなく <強い 実際の企業プロジェクトのハンズオンのヒント そのまま持っていって使うことができる
- 実際のインターフェイスの呼び出し 関連する機能を実装している
- 優れたラッピングのヒント(このプロジェクトは 元テンセント フロントエンドアーキテクト (元テンセントフロントエンドアーキテクトの指導のもとで構築された)
- ポットホールを踏み抜き、よりスムーズな開発を支援します
- すべてのコードの感度を下げ、中途半端な理解に陥らないようにします。
プロジェクトプレビュー
-
ログインページ効果
-
ログイン時の遷移効果
-
ログインに成功し、ページに移動します。
-
左サイドナビゲーションと右サイドテーブルの効果
-
ご覧いただいているのは 標準的なバックエンド管理システム
-
このシンプルなページは、強力なコードに裏付けられています。
プロジェクトのテクノロジースタックの概要
- 開発ツール:vscode(推奨フロントエンド開発ツール)
- Vueのバージョン。V 2.6.11
- vue-router: V 3.2.0
- 要素 ui のバージョンです。V 2.15.1
- インターフェイスデバッグ:axios library V 0.21.1
- vue-cli (scaffolding) のバージョン。V 4.5.0
- ノードのバージョンです。V 13.14.0
- node-sassです。V 4.12.0
- sass-loader。V 8.0.2
- babel-eslint: V 10.1.0
1. ルーティングの設定
routerフォルダーの下に、index.jsの設定
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '... /views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
requireAuth: true
},
children: [
// Student data
{
path: '/home/studentData',
name: 'studentData',
meta: {
requireAuth: true
},
component: () => import('... /views/studentData/studentData.vue')
},
// Teacher data
{
path: '/home/teacherData',
name: 'teacherData',
meta: {
requireAuth: true
},
component: () => import('. /views/teacherData/teacherData.vue')
},
]
},
{
path: '/login',
name: 'login',
component: () => import('. /views/login/login.vue'),
// child route
children: [
]
}
]
// Multiple clicks on the same navigation will report an error, so this code has been added
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
const router = new VueRouter({
routes
})
// The router will be used elsewhere, so export it
export default router
- 注)このような項目があるため は、中段のテーブル部分のみがトグルします。 そのため、ルーティングの設定には <マーク 親子ルーティングパターン
- 親ルート:home.vueには、1.左ナビゲーション、2.ヘッダー情報バー、3.フォームセクションのコンテナが含まれています。
-
ビューファイルのディレクトリは以下のように設定されています。(あまり熟練していない場合は、まず私の設定に従いましょう)
2. ログインページの設定
login.vue (現在は純粋な静的ページ。後でインターフェースとメソッドを追加)
<template>
<div class="login-box">
<div class="form-con">
<h2>Vue+element ui management system in action</h2>
<div class="label">
<el-input placeholder="Please enter account number" v-model="userName">
<template slot="prepend"><i class="el-icon-user"></i></template>
</el-input>
</div>
<div class="label">
<el-input placeholder="Please enter your password" v-model="password" show-password @keyup.enter.native="loginFn()">
<template slot="prepend"><i class="el-icon-lock"></i></template>
</el-input>
</div>
<div class="label">
<el-button class="login-btn" type="primary" @click="loginFn()"
>login</el-button
>
</div>
</div>
</div>
</template>
<script>
export default {
name: "login",
data() {
return {
userName: "",
password: "",
verify: "",
};
},
};
</script>
<style lang="scss" scope>
.login-box {
width: 100%;
height: 100%;
display: flex;
text-align: center;
background: url("~@/assets/4.jpg") no-repeat;
background-size: 100% 100%;
.form-con {
h2 {
color: #ffffff;
// color: $colorRed;
}
width: 360px;
height: 420px;
margin: 150px auto auto auto;
.label {
margin: 40px 0;
.login-btn {
width: 100%;
}
}
}
}
</style>
3. APIレイヤーの設定(インターフェース設定)
-
メンテナンス性を考慮し、階層的にデザインされたインターフェース 以下の4つの基本ファイルが用意されます(これらは推奨の必須アイテムで、残りは必要に応じて追加可能です)。
-
このうち最初の3つのファイルを書き込んだ後は、基本的に動かす必要はなく、きっぱり、かっこいい
-
アイデア ディープデカップリング と 高い再利用性
3.1 Service.jsの設定
- このファイルは、バックエンドの処理と、すべてのインターフェイス(各種インターセプト処理、ステータス処理など)の統一を担当する。
import axios from 'axios'
import vue from '... /main.js'
// Get the token from local
function getTokenByLocal() {
let token = sessionStorage.getItem('token');
return token;
}
const service = axios.create({
baseURL: '/sys',
// withCredentials: true,
timeout: 5000,
})
// Request interception
service.interceptors.request.use(
config => {
if (getTokenByLocal()) {
// Here you can set all interface headers headers
config.headers['token'] = getTokenByLocal();
}else{
// window.location.href="/login";
}
return config
},
error => {
return Promise.reject(error)
}
)
// Response interception
service.interceptors.response.use(
response => {
let res = response.data;
// console.log(res);
// status code handling
if (res.code == '200') {
// location.href = "home/login";
}
// If -101 means the user is not logged in
if(res.code == '-101'){
vue.$router.push('/login');
}
return Promise.resolve(res);
},
error => {
return Promise.reject(error)
}
)
export default service;
3.2 Common.jsの設定
- このファイルが行うことはただ一つです。 プロジェクト内のすべてのインターフェイスのパススルーの取り扱いを統一します。
- 一般的に言って、あまり派手なパススルーはないでしょう。
// Bring in service.js
import service from '. /service.js'
// post request 80% low coupling high reusability
export function requestOfPost(url, data){
return service.post(url, data);
}
3.3 api.jsの設定
- このファイルは、非同期を処理するためのプロミスを追加したセカンダリラッパーです。
import {requestOfPost} from '. /common.js'
export function postRequest(url, data){
return new Promise((resolve, reject) => {
requestOfPost(url, data).then(res => resolve(res))
.catch(error => reject(error))
})
}
3.4 url.jの設定
- このファイルは、すべてのインターフェイスのパスの統一管理、それ以外のプロジェクト東1西1トラブルを維持するために(建築家は言った、我々は反論する勇気がない、慎重にそれについて考え、それはまた正しいです)
- プロジェクトに百以上のインターフェイスがある場合は、2つに分割することができます。 コメントを追加することを忘れないでください。
const url = {
// login
login: '/login',
// Student list
getClassmates: '/getClassmates'
}
export default url;
4. クロスドメインハンドリング
-
一般的に言って、ローカル開発はクロスドメインでインターフェイスを設定する必要があり、バックエンドは一般的にそれに対処するには怠慢すぎる(謙虚なフロントエンドの無力さ)。
-
プロジェクトの一番外側のレイヤーにファイルを追加する。 <マーク vue.config.js
-
構成は以下の通りです。
module.exports = {
devServer: {
compress: false,
open: true,
proxy: {
'/sys': {
// proxy address
target: 'http://api.gebilaowang.com',
// websocket (usually used for instant messaging, games, not needed here, so don't open)
ws: false,
// whether to allow cross-domain
changeOrigin: true,
// rewrite
pathRewite: {
'/sys': '/'
}
}
}
}
}
5. これで楽しくインターフェイスをチューニングすることができます
login.vueのコードを追加しました。
<script>
// This is a globally defined transition method
import { loadingShow } from ". /... /common/js/common.js";
import url from "... /... /request/url.js";
import { postRequest } from ". /... /request/api.js";
export default {
name: "login",
props: {
msg: String,
},
data() {
return {
userName: "",
password: "",
verify: "",
};
},
methods: {
// Login method
loginFn() {
if (!this.userName) {
this.msgFn("warning", "Please enter your account name");
return;
} else if (!this.password) {
this.msgFn("warning", "Please enter password");
return;
} else {
// Loading animation
loadingShow();
let data = {
userName: this.userName,
passWord: this.password
};
postRequest(url.login, data).then(
(res) => {
// animation hide
loadingHide();
if (res.code == 500) {
this.msgFn("error", res.msg);
return;
}
// token is stored in sessionStorage
sessionStorage.setItem("token", res.token);
// page jump
setTimeout(() => {
this.$router.push("/home/studentData");
}, 500);
},
(error) => {
console.log(error);
}
);
}
},
// popup window
msgFn(type, text) {
this.$message({
message: text,
type: type,
});
},
},
created() {
},
};
</script>
6. main.jsに必要な構成
- ui要素に要素を導入して登録する
- グローバルなアニメーション設定
import Vue from 'vue'
import App from '. /App.vue'
import router from '. /router'
import {
Button,
Container,
Header,
Aside,
Main,
Footer,
Input,
Loading,
Message,
Menu,
Submenu,
MenuItem,
MenuItemGroup,
Dropdown,
DropdownMenu,
Table,
TableColumn,
DropdownItem,
Form,
FormItem,
Select,
Option,
OptionGroup,
DatePicker,
Pagination,
MessageBox,
Popover,
Tag,
Switch,
Dialog
} from 'element-ui';
Vue.use(global)
Vue.use(Button)
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main)
Vue.use(Footer)
Vue.use(Input)
Vue.use(Menu)
Vue.use(Submenu)
Vue.use(MenuItem)
Vue.use(MenuItemGroup)
Vue.use(Dropdown)
Vue.use(Table)
Vue.use(TableColumn)
Vue.use(DropdownMenu)
Vue.use(DropdownItem)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Select)
Vue.use(Option)
Vue.use(OptionGroup)
Vue.use(DatePicker)
Vue.use(Pagination)
Vue.use(Popover)
Vue.use(Dialog);
Vue.use(Tag)
Vue.use(Switch)
Vue.use(Loading.directive);
// Add global methods
Vue.prototype.$loading = Loading.service;
Vue.prototype.$message = Message;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$msgbox = MessageBox;
Vue.config.productionTip = false;
let vue = new Vue({
router,
render: h => h(App)
}). $mount('#app')
export default vue;
7. ルートブロックを設定する
- コンテンツが少ない場合はmain.jsに入れる
- ルータを忘れずに導入する
router.beforeEach((to, from, next) => {
// Take token as an example
let token = sessionStorage.getItem('token');
// requires authentication before it can enter requireAuth
if (to.meta.requireAuth) {
if (token) {
next();
// Accessed successfully
} else {
// jump to the specified page
next({
path: '/login'
})
}
} else {
// Smooth entry
next();
}
})
8. グローバルメソッドの設定
-
ストレージディレクトリは、以下の通りです(建築家が言っていたことで、もう少し考えたら、ここに置くのが理にかなっています)。
- 参考までにグローバルなメソッドをあげると、後続のメソッドはこれに続く(まだ非常に甘い)。
import vue from '... /... /main.js'
// Mask layer control
export function loadingShow(close){
const loadingFade = vue.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0, 0.7)'
})
if(close){
loadingFade.close();
}
}
9. 親ページの設定(home.vue)
- 必要な人がいそうな気がするので、コードはそのまま掲載(作者が必要だと思うから必要なのです)
<template>
<div class="container-big">
<el-container class="container">
<el-aside width="220px">
<el-menu class="menu" :default-active="index">
<el-submenu index="1">
<template slot="title"><i class="el-icon-s-home"></i>home</template>
<el-menu-item index="1-1" @click="toRoute('/home/studentData', 'student data')"
>studentData</el-menu-item
>
</el-submenu>
<el-submenu index="2">
<template slot="title"
><i class="el-icon-s-cooperation"></i>Academic Affairs / Administration</template
>
<el-submenu index="2-2">
<template slot="title">Role Management</template>
<el-menu-item
index="2-2-1"
@click="toRoute('/home/teacherData', 'Teacher Management')"
>
Teacher management</el-menu-item
>
<el-menu-item
index="2-2-2"
@click="toRoute()"
>
Teacher review</el-menu-item
>
</el-submenu>
<el-submenu index="2-3">
<template slot="title">other-management</template>
<el-menu-item
index="2-3-1"
@click="
toRoute()
"
>
Academic Administration</el-menu-item
>
<el-menu-item
index="2-3-3"
@click="
toRoute(
'/home/shopList',
' / operations management / store management / shop list',
'shopList',
'2-3-3'
)
"
>
Toilet sweep management</el-menu-item
>
</el-submenu>
</el-submenu>
</el-menu>
</el-aside>
<el-container>
<el-header style="text-align: right; font-size: 14px">
<div class="optimization">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"> operation </i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="logOut()"
>LogoutLogout</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
<span>{{ userName }}</span>
</div>
<div class="router-con">
<div>
<span>xxx company operations management system</span>
</div>
<h2>{{pageName}}</h2>
</div>
</el-header>
<el-main>
<router-view> </router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
name: "home",
data() {
return {
userName: "",
index: "1-1",
pageName: ''
};
},
created() {
// You can fetch permission-related data here
},
methods: {
// Jump to individual pages
toRoute(url, name) {
this.$router.push(url);
this.pageName = name;
},
// Logout
logOut() {
// Jump to the login page
this.$router.push("/login");
// Usually you need to clear some cached data for the user here
},
},
};
</script>
<style lang="scss" scope>
.logo {
overflow: hidden;
padding: 10px 0px 10px 20px;
cursor: pointer;
img {
float: left;
margin-top: 10px;
}
p {
float: left;
margin: 12px 0 0 12px;
color: #fff;
font-weight: 600;
font-size: 20px;
vertical-align: middle;
animation: fade-in;
animation-duration: 0.3s;
}
}
.el-submenu .el-menu-item {
text-align: left;
height: 40px;
line-height: 40px;
// margin-left: 10px;
}
.menu {
.el-submenu {
.el-submenu__title {
padding-left: 30px;
}
.el-menu {
.el-submenu__title {
padding-left: 50px !important;
}
}
}
}
.el-header {
color: #333;
border-bottom: 1px solid #d3d3d3;
background: #fff;
padding: 0;
box-shadow: darkgrey 5px 0 5px 1px; //border-shadow
.optimization {
height: 60px;
line-height: 60px;
padding: 0 20px;
curso
- コードは詳細にコメントされているので、ここでは説明しませんが
- あなたのファイルにすべてコピーして、効果を確認することができます(とてもスイートでしょう?)
10. よくある質問 よくある質問とその回答
- 何かが間違ってインストールされている(外国のネットワークが不安定な場合があります、あなたはタオバオミラーを設定することができます)。
- 何かが動作していない(バージョンの問題に注意してください)
-
vue.config.js
ファイルは有効になりません。
<マーク
必ずサービスを再起動する
と再コンパイル) - 一部のコンポーネントでスタイルが正しく表示されない( main.js (で導入や登録が行われているかどうかを確認する)。
- 一部のモジュールが見つからないという報告(ファイル格納パス、導入パスが正しいか確認する)
- その他の課題(可能な限り 直接プライベートメッセージ (一日に数回チェックし、見かけたらすぐに返信します)。
- 誰もが読めるように理解するために努力するためには、問題ないでしょう。この記事は、完了するために多くの努力を取った(喫煙レッドターザン、夜更かし)それはあなたの助けになることを願っています。
- 三社の波を忘れずに~、いいね!、コメント、フォロー
- 一度に読み切れない場合は、ブックマークしておくといいですよ〜。
-
いつも応援ありがとうございます!これからも良質な記事を必ずアウトプットしていきます〜。
関連
-
JSエラーです。Uncaught TypeError: nullのプロパティ'addEventListener'を読み取ることができません。
-
JSON の位置 1 に予期しないトークン o がある エラーの理由
-
(解決済み)JSONの1番目の位置で予期しないトークンoが発生した。
-
JSON の位置 1 に予期しないトークン o がある エラーの理由
-
エラー [ERR_HTTP_HEADERS_SENT]: クライアントに送信された後のヘッダを設定できない
-
JSONの位置0にある予期しないトークン エラーが解決されました。
-
Uncaught TypeError: XXX は解決された関数ではありません。
-
CSS3 transformの回転角度の度数をjsで取得する方法、マトリックス解析
-
layui (laydate) を使用すると、Cannot read property 'appendChild' of undefined というエラーが、どこをクリックしても表示されます。
-
JSネイティブAjaxとjQuery Ajaxをコード例で紹介します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
nodeJS がエラーを報告する JSON の位置 1 に予期しないトークン o がある
-
JSON変換エラーです。Uncaught SyntaxError: JSON.parse_乐夫天命兮的客-プログラマーベイビーで位置1に予期しないトークンo。
-
JSONの位置0にある予期しないトークン<がエラー解決になりました。
-
JS(ネイティブjs、jqメソッド)要素属性(カスタム属性)取得、属性(カスタム属性)削除
-
タイマーのエラーを解決する:Uncaught TypeError: that.setAttribute is not function
-
jquery Datatable パラメータとその使用方法
-
Javascriptにおけるdocument.execCommand()の使用法
-
bootstrap-treeview ツリーパラメータ詳細
-
Uncaught (in promise)は一般的にpormiseの書き方に問題がある。
-
document.getElementById は関数ではありません。