vue3.0 後臺管理系統 框架搭建 vue3.0全局掛載http、api、config

vue的重要性可想而知,提前學習vue3.0,沒毛病。本文會帶大家瞭解vue3.0的構建工程、antd引入、生命週期、data雙向數據綁定使用、方法使用、計算屬性、監聽、組件引入、組件傳值、路由傳值等知識點,本人菜鳥,大佬多多指導。廢話少說,通過實操做一個登錄、列表、詳情界面直接上代碼。

github源碼: https://github.com/parchments/vue3-admin-template

效果預覽:登錄頁、首頁、列表頁、詳情頁

首頁

列表頁

詳情頁

1、項目搭建

  1. 安裝node就不說咯,必備。此外需要安裝vue-cli4代以上最新腳手架,可以通過執行如下npm 命令安裝/更新腳手架版本
腳手架升級: npm update @vue/cli
初次安裝:   npm i @vue/cli -g

根據自己需求選擇需要預先安裝的插件

vue create \[projectName\]

怎麼知道自己正確安裝了vue3.0,請看vue3.0的main.js,vue2.0引入vue是import Vue from 'vue',vue3.0則是解構引入,看到解構引入代表此項目爲vue3.0,幹得漂亮,繼續。。。

vue3.0全局掛載http、api、config

順便提一句,如果vue3.0+ts開發的話,全局掛載需要如下掛載方式

在文件 main.ts 添加 帶有 + 符號後代碼

//  main.ts
import { createApp } from "vue";
import App from "./App.vue";
\+ import axios from "axios";

const app = createApp(App);
\+ app.config.globalProperties.$http = axios;
app.mount("#app")
在文件 shims-vue.d.ts添加 帶有 + 符號後代碼

//  shims-vue.d.ts

declare module "*.vue" {
  import { defineComponent } from "vue";
  const component: ReturnType<typeof defineComponent>;
  export default component;
}

\+ declare module "@vue/runtime-core" {
\+  import { AxiosInstance } from "axios";
\+  interface ComponentCustomProperties {
\+    $http: AxiosInstance;
\+  }
\+ }

2、安裝並引入antd

$ npm i --save ant-design-vue@next

//需要按需引入的話安裝插件 babel-plugin-import 然後配置 babel.config.js$ npm i --save babel-plugin-import

完整引入

import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/antd.css';

const app = createApp();
app.config.productionTip = false;

app.use(Antd);

以上代碼便完成了 Antd 的引入。需要注意的是,樣式文件需要單獨引入。

**局部導入組件**

import { createApp } from 'vue';
import { Button, message } from 'ant-design-vue';
import App from './App';

const app = createApp();
app.config.productionTip = false;

/\* Automatically register components under Button, such as Button.Group */
app.use(Button);

app.config.globalProperties.$message = message;

如果需要按需加載,則配置`ant-design-vue`

根目錄打開`babel.config.js`文件,將裏面的內容修改爲

module.exports = {
  presets: \["@vue/cli-plugin-babel/preset"\],
  plugins: \[
    //以下是配置按需加載
    \[
      "import",
      { 
        libraryName: "ant-design-vue", 
        libraryDirectory: "es", 
        style: "css"//爲true時加載的是less文件
      }
    \]
  \]
}

目前我是用全局引入的方式引入antd,大家根據自己需求引入即可。

3、頁面佈局

app.vue頁面

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style lang="less">
#app {
  text-align: center;
}
</style>

login頁面: 涉及data定義,響應式數據、生命週期、方法調用、實例獲取(即是vue2.x的this)

//login
<template>
	<div class="box">
		<h1>登錄</h1>
		<h2>{{name}}</h2>
		<a-form class="form" layout="inline">
			<a-form-item label="賬號">
				<a-input v-model:value="account" type="text" placeholder="請輸入賬號"/>
			</a-form-item>
			<a-form-item label="密碼">
				<a-input v-model:value="password" type="password" placeholder="請輸入密碼"/>
			</a-form-item>
			<h3>輸入賬號密碼,{{count}} 秒後登錄</h3>
			<a-button @click="login()" block :disabled="account === '' || password === ''" type="primary">登錄</a-button>
		</a-form>
	</div>
</template>

<script>
	//vue-cli 4.5.4創建的3.0
	// import { reactive } from '@vue/composition-api' //會提示報錯 export 'default' (imported as 'Vue') was not found in 'vue'
	import { reactive, toRefs, getCurrentInstance, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured} from 'vue' //vue-cli 4.5.4 之後vue3.0集成了@vue/composition-api
	export default {
		name: 'login',
		components: {
			
		},
		
		//始化數據,介於beforeCreate與created之間,相當於beforeCreate、created的合併
		setup() {
			//setup(props,context)函數  默認兩個屬性props,context 屬性和上下文   setup函數中無法訪問到this   
			//創建處理響應式數據對象 類似date  需要先導入
			const state = reactive({
				count: 3,
				name: '我是響應式數據name',
				account: '',//賬號
				password: ''//密碼
			})
			//獲取當前路由實例
			//Vue 3.0 中通過 getCurrentInstance 方法獲取當前組件的實例,然後通過 ctx 屬性獲得當前上下文,ctx.$router 是 Vue Router 實例,裏面包含了 currentRoute 可以獲取到當前的路由信息
			const { ctx } = getCurrentInstance();
			console.log(toRefs)
			//登錄方法
			const login = () => {
				// state.count++;
				
				console.log(ctx);
				let {account,password} = state;//對象解構
				if(account=== "" || password===""){
					alert('賬號密碼不能爲空')
				}else{
					setInterval(()=>{
						state.count--;
					},1000)
					setTimeout(()=>{
						ctx.$router.push('/index');
					},3000);
				}
				// return
			}
			
			//以下是生命週期
			//組件掛載前
			onBeforeMount( () => {
				console.log('onBeforeMount,組件掛載前,相當於beforeMount')
			})
			//實例掛載完畢
			onMounted( () => {
				console.log('onMounted,實例掛載完畢,相當於mounted')
			})
			//響應式數據變化前
			onBeforeUpdate( () => {
				console.log('onBeforeUpdate,響應式數據變化前,相當於beforeUpdate')
			})
			//響應式數據變化完成
			onUpdated( () => {
				console.log('onUpdated,響應式數據變化完成 ,相當於updated')
			})
			//實例銷燬前
			onBeforeUnmount( () => {
				console.log('onBeforeUnmount,實例銷燬前 ,相當於beforeDestroy')
			})
			//實例已銷燬
			onUnmounted( () => {
				console.log('onUnmounted,實例已銷燬 ,相當於destroyed')
			})
			//錯誤數據捕捉
			onErrorCaptured( () => {
				console.log('onErrorCaptured,錯誤數據捕捉')
			})
			//setup函數的返回值 導出
			return {
				//...state,  //如果沒有用toRefs方法的話,是不能把reactive創建出來的數據變成響應式數據的  需要響應式就是要加上toRefs 否則不需要
				...toRefs(state),//把reactive創建出來的數據變成響應式數據
				login
			}
		}
	}
</script>
<style lang="less" scoped>
	.box{
		width: 50%;
		margin: 0 auto;
		padding-top: 200px;
		.form{
			width: 60%;
			margin: 0 auto;
			padding-top: 30px;
		}
	}
</style>

看得出來跟vue2.x的結構已經有很大區別了,例如setup、方法使用等等,setup是Composition API的入口,Vue3.0提供的新屬性,可以在setup中使用Composition API,在上文代碼中我們在setup中通過reactive初始化了一個響應式數據,然後通過return返回了一個對象,對象中包含了聲明的響應式數據和一個方法。
 

setup函數有兩個參數,分別是props和context, setup(props,context);

props組件外部傳入進來的屬性

export default {
  props: {
    title: {
      type: String
    }
  },
  setup(props) {
    //組件傳入的值
    console.log(props.title)
  }
}

context是一個對象,裏面包含了三個屬性,分別是 attrs、slots、emit

attrs與Vue2.0的this.$attrs是一樣的,即外部傳入的未在props中定義的屬性。對於attrs與props一樣,我們不能對attrs使用es6的解構,必須使用attrs.name的寫法。

slots對應的是組件的插槽,與Vue2.0的this.$slots是對應的,與props和attrs一樣,slots也是不能解構的。

emit對應的是Vue2.0的this.$emit, 即對外暴露事件。

home.vue頁面

![](https://oscimg.oschina.net/oscnet/up-0e5c5181a088f6b3bd925effb7caf816720.png)

<template>
	<div>
		<Nav />
		<router-view></router-view>
		<br/>
		<br/>
		<br/>
		<br/>
		<a-button @click="back()">退出登錄</a-button>
	</div>
</template>

<script>
	// import { reactive } from '@vue/composition-api' //會提示報錯 export 'default' (imported as 'Vue') was not found in 'vue'
	import { reactive,toRefs,getCurrentInstance } from 'vue' //vue-cli 4.5.4 之後vue3.0集成了@vue/composition-api
	import Nav from '../../components/nav.vue'
	export default {
		name: 'home',
		components: {
			Nav
		},
		
		//始化數據,介於beforeCreate與created之間,相當於beforeCreate、created的合併
		setup(props,context) {
			console.log(props,context);
			//函數  默認兩個屬性props,context 屬性和上下文   setup函數中無法訪問到this   
			//創建處理響應式數據對象 類似date  需要先導入
			const state = reactive({
				
			})
			//獲取當前路由實例
			//Vue 3.0 中通過 getCurrentInstance 方法獲取當前組件的實例,然後通過 ctx 屬性獲得當前上下文,ctx.$router 是 Vue Router 實例,裏面包含了 currentRoute 可以獲取到當前的路由信息
			const { ctx } = getCurrentInstance();
			//登錄方法
			const back =() => {
				ctx.$router.push('/login');
			}
			//setup函數的返回值 導出
			return {
				...toRefs(state),
				back
			}
		}
	}
</script>

index->index.vue頁面

<template>
	<div style="padding-top: 100px;">
		<h2>首頁內容</h2>
		<img src="../../../assets/logo.png" alt="">
	</div>
</template>

<script>
	import { reactive, toRefs, getCurrentInstance } from 'vue'
	export default {
		name: 'index',
		// components: {

		// },
		setup() {
			const state = reactive({
				
			})
			//獲取當前路由實例
			const { ctx } = getCurrentInstance();
			console.log(ctx)
			//setup函數的返回值 導出
			return {
				...toRefs(state)
			}
		}
	}
</script>

accountList.vue 列表頁面(計算屬性)

<template>
	<div style="margin-top: 100px;">
		<ti :title="title"></ti>
		<h3>列表請求數據中...{{count}}秒後顯示</h3>
		<a-table :data-source="list" :pagination="false" style="width: 60%; margin: 0 auto 30px;">
			<a-table-column key="account" title="account" data-index="account" />
			<a-table-column key="password" title="password" data-index="password" />
			<a-table-column key="action" data-index="action">
				<template v-slot="{record}">
					<span>
						<a @click="goToLink(record.id)">詳情</a>
					</span>
				</template>
			</a-table-column>
		</a-table>
		<a-input type="text" v-model:value="leftValue" placeholder="leftValue" style="width: 100px;"/>
		<a-input type="text" v-model:value="rightValue" placeholder="rightValue" style="width: 100px;"/>
		<div>
			計算屬性輸出的結果是:{{resultValue}}
		</div>
		<!\-\- <div>
			<h2>Clicked {{ count }} times</h2>
			<h2>Watch Count is {{ watchCount }}</h2>
			<button @click="increase">Click</button>
		</div> -->
	</div>
</template>

<script>
	import {
		reactive,
		toRefs,
		getCurrentInstance,
		onMounted,
		computed
	} from 'vue'
	import title from './component/title.vue'
	export default {
		name: 'accountList',
		components: {
			'ti': title
		},
		setup(props, context) {
			console.log('propss,context', props, context)
			const state = reactive({
				title: '我是子組件的值', //子組件
				list: \[\],
				count: 3,
				leftValue: 0,
				rightValue: 0,
				//計算屬性
				resultValue: computed(() => {
					return Number(state.leftValue) + Number(state.rightValue);
				})
			})
			// const count1 = ref(0);
			// const watchCount = ref(0);
			// function increase () {
			//   count1.value++;
			// };
			// watch( () => count1.value,
			// 	(val) => {
			// 		watchCount.value = val;
			// 	}
			// );
			//獲取當前路由實例
			const {
				ctx
			} = getCurrentInstance();
			console.log('列表實例', ctx)

			function goToLink(index) {
				ctx.$router.push({
					path: '/accountList/detail',
					query: {
						id: index
					}
				})
			}

			function getList() {
				// axios請求
				let timer1 = setInterval(() => {
					state.count--;
					if (state.count < 1) {
						clearInterval(timer1)
						return
					}
				}, 1000)
				console.log('請求列表數據')
				//模擬異步請求
				let timer2 = setTimeout(() => {
					state.list = \[{
							id: 1,
							account: 'admin',
							password: '111111'
						},
						{
							id: 2,
							account: 'chushi',
							password: 'chushi-111'
						},
						{
							id: 3,
							account: 'six',
							password: '666'
						}
					\]
					clearTimeout(timer2)
				}, 2000)

				//以下爲普通列表請求方法
				// async getList(params) {
				// 	state.loading = true;
				// 	try{
				// 		let res = await ctx.$api.systemManage.getList(params);
				// 		if (res.data.retcode === ctx.$config.RET\_CODE.SUCCESS\_CODE) {
				// 			let data = res.data.data;
				// 			if (data.length > 0) {
				// 				state.tableData = data;
				// 				state.paginationParams.pageSize = data.pageSize; //每頁的數量
				// 				state.paginationParams.size = data.size; //當前頁的數量
				// 				state.paginationParams.total = data.total; //總條數
				// 				state.paginationParams.pages = data.pages; //總頁碼數
				// 			} else {
				// 				state.tableData = \[\];
				// 			}
				// 		} else {
				// 			ctx.$Message.error('請求成功,暫無數據');
				// 		}
				// 		state.loading = false;
				// 	}catch(e){
				// 		state.loading = false;
				// 		ctx.$Message.error('暫無數據');
				// 		console.log(e);
				// 	}
				// }
			}
			onMounted(() => {
				getList();
			})
			//setup函數的返回值 導出
			return {
				...toRefs(state),
				goToLink,
			}
		}
	}
</script>

detail 詳情頁面(路由傳參)

<template>
	<div>
		<h3>請求參數id爲{{id}}的數據</h3>
		<router-link to="/accountList">返回列表</router-link>
	</div>
</template>

<script>
	import { reactive, toRefs, getCurrentInstance } from 'vue'
	import { useRoute } from 'vue-router'
	export default {
		name: 'detail',
		components: {

		},
		setup(props,context) {
			const state = reactive({
				id: ''
			})
			const { ctx } = getCurrentInstance();//獲取實例
			const { query } = useRoute();//獲取路由參數
			console.log(query)
			state.id = query.id;
			console.log('詳情',ctx,context)
			//setup函數的返回值 導出
			return {
				...toRefs(state)
			}
		}
	}
</script>

相信大家對vue3.0基礎用法有了初步的認識,菜鳥的我也在不斷學習中,持續更新ing

官網文檔:https://v3.cn.vuejs.org/api/application-config.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章