vue(ant-design-vue)組件嵌套方式
-
axios跨域
-
新建http文件夾
-
http/apis.js
-
//將我們http.js中封裝好的 get,post.put,delete 導過來 import {axios_get, axios_post, axios_delete, axios_put} from './index.js' // 書籍管理接口 // export const getBookList = (params, headers) => axios_get("/books/book/", params, headers) //用戶 //獲取用戶信息 export const getUser = (params, headers) => axios_get("/user/user/", params, headers) //登錄接口 export const postLogin = (params, headers) => axios_post("/user/login/", params, headers) //注冊接口 export const postRegister = (params, headers) => axios_post("/user/register/", params, headers) //搜索 export const postSearch = (params, headers) => axios_post("/user/search/", params, headers) //刪除 export const delUser = (params, headers) => axios_delete("/user/user/" + params.id + '/', headers) //修改 export const upUser = (params, headers) => axios_put("/user/user/" + params.id + '/', params, headers)
-
-
http/index.js
-
import axios from 'axios' // 第一步:設置axios axios.defaults.baseURL = "http://192.168.56.100:8888/" //全局設置網絡超時 axios.defaults.timeout = 10000; //設置請求頭信息 axios.defaults.headers.post['Content-Type'] = 'application/json'; axios.defaults.headers.put['Content-Type'] = 'application/json'; // 第二:設置攔截器 /** * 請求攔截器(當前端發送請求給后端前進行攔截) * 例1:請求攔截器獲取token設置到axios請求頭中,所有請求接口都具有這個功能 * 例2:到用戶訪問某一個頁面,但是用戶沒有登錄,前端頁面自動跳轉 /login/ 頁面 */ axios.interceptors.request.use( config => { // 每次發送請求之前判斷是否存在token,如果存在,則統一在http請求的header都加上token,不用每次請求都手動添加了 const token = localStorage.getItem("token") // console.log(token) if (token) { config.headers.Authorization = 'JWT ' + token } return config; }, error => { return Promise.error(error); }) axios.interceptors.response.use( // 請求成功 res => res.status === 200 || res.status === 204 || res.status === 202 ? Promise.resolve(res) : Promise.reject(res), // 請求失敗 error => { if (error.response) { // 判斷一下返回結果的status == 401? ==401跳轉登錄頁面。 !=401passs // console.log(error.response) if (error.response.status === 401) { // 跳轉不可以使用this.$router.push方法、 // this.$router.push({path:'/login'}) window.location.href = "http://127.0.0.1:8888/" } else { // errorHandle(response.status, response.data.message); return Promise.reject(error.response); } // 請求已發出,但是不在2xx的范圍 } else { // 處理斷網的情況 // eg:請求超時或斷網時,更新state的network狀態 // network狀態在app.vue中控制着一個全局的斷網提示組件的顯示隱藏 // 關於斷網組件中的刷新重新獲取數據,會在斷網組件中說明 // store.commit('changeNetwork', false); return Promise.reject(error.response); } }); // 第三:封裝axios請求 // 3.1 封裝get請求 export function axios_get(url, params) { return new Promise( (resolve, reject) => { axios.get(url, {params: params}) .then(res => { // console.log("封裝信息的的res", res) resolve(res.data) }).catch(err => { reject(err.data) }) } ) } // 3.2 封裝post請求 export function axios_post(url, data) { return new Promise( (resolve, reject) => { // console.log(data) axios.post(url, JSON.stringify(data)) .then(res => { // console.log("封裝信息的的res", res) resolve(res.data) }).catch(err => { reject(err.data) }) } ) } // 3.3 封裝put請求 export function axios_put(url, data) { return new Promise( (resolve, reject) => { // console.log(data) axios.put(url, JSON.stringify(data)) .then(res => { // console.log("封裝信息的的res", res) resolve(res.data) }).catch(err => { reject(err.data) }) } ) } // 3.4 封裝delete請求 export function axios_delete(url, data) { return new Promise( (resolve, reject) => { // console.log(data) axios.delete(url, {params: data}) .then(res => { // console.log("封裝信息的的res", res) resolve(res) }).catch(err => { reject(err) }) } ) }
-
-
-
在components\index.vue
-
<template> <div> <a-layout id="components-layout-demo-top-side" :selected-keys="[current]" > <a-layout-header class="header"> <div class="logo"/> <a-menu theme="dark" mode="horizontal" :default-selected-keys="['1']" :style="{ lineHeight: '64px' }" > <a-menu-item key="1"> nav 1 </a-menu-item> <a-menu-item key="2"> nav 2 </a-menu-item> <a-menu-item key="3" style="margin-left: 80%"> <Header></Header> </a-menu-item> </a-menu> </a-layout-header> <a-layout-content style="padding: 0 50px"> <a-breadcrumb style="margin: 16px 0"> <a-breadcrumb-item>Home</a-breadcrumb-item> <a-breadcrumb-item>List</a-breadcrumb-item> <a-breadcrumb-item>App</a-breadcrumb-item> </a-breadcrumb> <a-layout style="padding: 24px 0; background: #fff"> <a-layout-sider width="200" style="background: #fff"> <a-menu mode="inline" :default-selected-keys="['1']" :default-open-keys="['sub1']" style="height: 100%" @click="handleClick" > <a-sub-menu key="sub1"> <span slot="title"><a-icon type="user"/>用戶模塊</span> <a-menu-item key="test"> 測試 </a-menu-item> <a-menu-item key="usermanage"> 用戶管理 </a-menu-item> </a-sub-menu> <a-sub-menu key="sub2"> <span slot="title"><a-icon type="laptop"/>工單模塊</span> <a-menu-item key=""> 工單管理 </a-menu-item> </a-sub-menu> <!-- <a-sub-menu key="sub3">--> <!-- <span slot="title"><a-icon type="notification"/>subnav 3</span>--> <!-- <a-menu-item key="">--> <!-- option9--> <!-- </a-menu-item>--> <!-- </a-sub-menu>--> </a-menu> </a-layout-sider> <a-layout-content :style="{ padding: '0 24px', minHeight: '280px' }"> <router-view></router-view> </a-layout-content> </a-layout> </a-layout-content> <a-layout-footer style="text-align: center"> </a-layout-footer> </a-layout> </div> </template> <script> import Header from "./layout/Header"; export default { components:{ Header, }, name: "index", data() { return { current: '1', } }, methods: { handleClick(e) { // console.log(e) this.current = e.key; this.$router.push({path: this.current}); }, }, //鈎子方法 mounted() { }, created() { }, //監聽屬性 watch: {}, //計算屬性 computed: {} } </script> <style scoped> #components-layout-demo-top-side .logo { width: 120px; height: 31px; background: rgba(255, 255, 255, 0.2); margin: 16px 28px 16px 0; float: left; } </style>
-
-
新建views文件夾
-
views/user-manage/ 新建componentes/ButtonComponent.vue
-
<template> <div> <a-button type="primary" @click="showModal" style="margin-left: 5px"> + 創建用戶 </a-button> <a-modal v-model="visible" title="Basic Modal" @ok="handleOk"> 用戶名 <a-input placeholder="" v-model="username"/> 密碼 <a-input placeholder="" v-model="password"/> 手機號 <a-input placeholder="" v-model="mobile"/> 電子郵箱 <a-input placeholder="" v-model="email"/> </a-modal> </div> </template> <script> import {postRegister} from "../../../http/apis"; export default { name: "ButtonComponent", data() { return { visible: false, username: '', password: '', mobile: '', email: '', } }, methods: { showModal() { this.visible = true; }, handleOk() { let params = { username: this.username, password: this.password, mobile: this.mobile, email: this.email, } this.$emit('addUser', params) // postRegister(params).then(res => { // console.log(res) // this.$router.go(0) // }) this.visible = false; }, }, //鈎子方法 mounted() { }, created() { }, //監聽屬性 watch: {}, //計算屬性 computed: {} } </script> <style scoped> </style>
-
-
views/user-manage/componentes/SearchComponent.vue
-
<template> <div> <div> <a-input-search class="a-input-search" placeholder="請輸入用戶名" enter-button @search="onSearch"/> <br/><br/> </div> </div> </template> <script> import {postSearch} from "../../../http/apis"; export default { name: "SearchComponent", data() { return { } }, methods: { onChange(date, dateString) { console.log(date, dateString); }, onSearch(value) { this.$emit('onSearch',value) // console.log(value); // postSearch({search_name: value}).then(res => { // console.log(res) // this.user_list = res // }) }, }, //鈎子方法 mounted() { }, created() { }, //監聽屬性 watch: {}, //計算屬性 computed: {} } </script> <style scoped> .a-input-search { width: 400px; margin-left: 35%; } .components-input-demo-size .ant-input { width: 200px; margin: 0 30px 30px 0; } </style>
-
-
views/user-manage/componentes/TableComponent.vue
-
<template> <div> <a-table :columns="columns" :data-source="data" :rowKey="record => record.id" :pagination="pagination"> <a slot="name" slot-scope="text">{{ text }}</a> <span slot="customTitle"><a-icon type="smile-o"/> 名字</span> <span slot="tags" slot-scope="tags"> <a-tag v-for="tag in tags" :key="tag" :color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'" > {{ tag.toUpperCase() }} </a-tag> </span> <span slot="action" slot-scope="text, record"> <a-button type="primary" @click="showModal(text)" style="margin-left: 5px"> 修改 </a-button> <a-modal v-model="visible" title="Basic Modal" @ok="handleOk(text)"> 用戶名 <a-input placeholder="" v-model="username" v-if="pk == uid" /> 用戶名 <a-input placeholder="" v-model="username" disabled="disabled" v-if="pk != uid" /> 手機號 <a-input placeholder="" v-model="mobile"/> 電子郵箱 <a-input placeholder="" v-model="email"/> </a-modal> <a-button type="danger" @click="delUser(text.id)">刪除</a-button> </span> </a-table> </div> </template> <script> import {delUser, getUser} from "../../../http/apis"; const columns = [ { dataIndex: 'username', // key: 'username', slots: {title: 'customTitle'}, scopedSlots: {customRender: 'name'}, }, { title: '最后一次登錄', dataIndex: 'date_joined', // key: 'mobile', }, { title: '電子郵箱', dataIndex: 'email', // key: 'email', }, { title: '手機號', // key: 'last_login', dataIndex: 'mobile', // scopedSlots: {customRender: 'tags'}, }, { title: '操作', // key: 'last_login', scopedSlots: {customRender: 'action'}, }, ]; // const data = [ // { // key: '1', // username: '戰三', // mobile: 18548789043, // email: '515@qq.com', // is_superuser: '0', // last_login:'2020-12-09' // }, // ]; export default { name: "TableComponent", props: ['data',], data() { return { // data: [], columns, visible: false, username: '', mobile: '', email: '', pk: '', pagination: { total: 0, pageSize: 2,//每頁中顯示10條數據 showSizeChanger: true, pageSizeOptions: ["5", "10", "20", "30"],//每頁中顯示的數據 showTotal: total => `共有 ${total} 條數據`, //分頁中顯示總的數據 }, uid: localStorage.getItem("uid") } }, methods: { showModal(text) { this.visible = true; this.username = text.username this.mobile = text.mobile this.email = text.email this.pk = text.id }, delUser(text) { this.$emit('delUser', text) // console.log(text) // delUser({id: text}).then(res => { // console.log(res) // this.$router.go(0) // }).catch(err => { // this.$router.go(0) // // }) }, handleOk(text) { console.log(text.id) let params = { username: this.username, mobile: this.mobile, email: this.email, password: '1', id: this.pk, } this.$emit('upUser', params) this.visible = false; }, }, //鈎子方法 mounted() { }, created() { // this.showUser() }, //監聽屬性 watch: {}, //計算屬性 computed: {} } </script> <style scoped> </style>
-
-
views/user-manage/ componentes/Crumbs
-
<template> <div> <a-breadcrumb separator="" class="a-breadcrumb"> <a-breadcrumb-item> nav 1 </a-breadcrumb-item> <a-breadcrumb-separator>:</a-breadcrumb-separator> <a-breadcrumb-item href=""> 用戶模塊 </a-breadcrumb-item> <a-breadcrumb-separator/> <a-breadcrumb-item href=""> 用戶管理 </a-breadcrumb-item> </a-breadcrumb> </div> </template> <script> export default { name: "Crumbs", data() { return {} }, methods: {}, //鈎子方法 mounted() { }, created() { }, //監聽屬性 watch: {}, //計算屬性 computed: {} } </script> <style scoped> .a-breadcrumb { /*background:red;*/ color: #1890ff; /*margin-top: -15px;*/ margin-left: -30px; } </style>
-
-
views/user-manage/ UserManage.vue
-
<template> <div> <div id="components-layout-demo-basic"> <a-layout> <a-layout-header style="background: #F0F2F5"> <Crumbs></Crumbs> <!-- 頁內標題--> </a-layout-header> <a-layout-content> <!-- 搜索組件--> <SearchComponent @onSearch="onSearch" ></SearchComponent> <!-- 添加按鈕--> <ButtonComponent @addUser="addUser" :visible=false > </ButtonComponent> </a-layout-content> <a-layout-footer> <!-- 展示 刪除按鈕 修改按鈕--> <TableComponent @showUser="showUser" @delUser="delUser" @upUser="upUser" :data="data" > </TableComponent> </a-layout-footer> </a-layout> </div> </div> </template> <script> import Crumbs from "./componentes/Crumbs"; import SearchComponent from "./componentes/SearchComponent"; import ButtonComponent from "./componentes/ButtonComponent"; import TableComponent from "./componentes/TableComponent"; import {delUser, getUser, postRegister, postSearch, upUser} from "../../http/apis"; const key = 'updatable'; export default { components: { Crumbs, SearchComponent, ButtonComponent, TableComponent, }, name: "UserManage", data() { return { visible: false, data: [] } }, methods: { //展示用戶 showUser() { getUser().then(res => { console.log(res) this.data = res.results }) }, //刪除 delUser(text) { const isDel = confirm("確定刪除嗎") if (isDel) { delUser({id: text}).then(res => { console.log(res) this.showUser() this.$message.info('刪除成功'); }).catch(err => { console.log(err) }) } else { } }, //搜索name mobile email onSearch(value) { console.log(value); postSearch({search_name: value}).then(res => { console.log(res) const hide = this.$message.loading('Action in progress..', 0); setTimeout(hide, 100); this.data = res }) }, //添加用戶 addUser(params) { console.log(params.id) postRegister(params).then(res => { console.log(res) this.showUser() this.visible = false; this.$message.loading({content: '添加中...', key}); setTimeout(() => { this.$message.success({content: '添加成功!', key, duration: 2}); }, 1000); }) this.visible = false; }, //修改用戶 upUser(params) { upUser(params).then(res => { console.log(res) this.showUser() this.visible = false; }) this.visible = false; }, }, //鈎子方法 mounted() { }, created() { this.showUser() }, //監聽屬性 watch: {}, //計算屬性 computed: {} } </script> <style scoped> .h3 { font-weight: 800; margin-left: -3%; margin-top: -20px; } </style>
-
-
登錄頁面 views/Login.vue
-
<template> <div width=300> <center><h1>登錄</h1></center> <a-form-item label="用戶名" v-bind="formlayout"> <a-input v-model="username"/> </a-form-item> <a-form-item label="密碼" v-bind="formlayout"> <a-input-password v-model="password" placeholder="input password" /> </a-form-item> <a-form-item v-bind="buttonlayout"> <a-button type="primary" @click="submit">登錄</a-button> </a-form-item> </div> </template> <script type="text/javascript"> import { postLogin } from '../http/apis'; export default{ data(){ return{ username:"", password:'', //表單樣式 formlayout:{ //標簽 labelCol:{ xs:{span:24}, sm:{span:8} }, //文本框 wrapperCol:{ xs:{span:14}, sm:{span:6} } }, //按鈕樣式 buttonlayout:{ //按鈕 wrapperCol:{ xs:{ span:24, offset:0 }, sm:{span:16,offset:8} } } } }, //自定義方法 methods:{ submit:function(){ var data={'username':this.username,'password':this.password} postLogin(data).then(resp => { console.log(resp) if(resp.token){ localStorage.setItem('token',resp.token) localStorage.setItem('username',resp.username) localStorage.setItem('uid',resp.id) this.$router.push('/') } }).catch(err=>{ console.log(err) alert('登錄失敗') }) } } }; </script> <style type="text/css"> </style>
-
-
全局配置src/main.js
-
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) // 使用ant-design-vue import Antd from 'ant-design-vue'; import 'ant-design-vue/dist/antd.css'; Vue.config.productionTip = false Vue.use(Antd); /* eslint-disable no-new */ new Vue({ el: '#app', router, components: {App}, template: '<App/>' }) //路由守衛 未登錄則登錄 router.beforeEach((to, from, next) => { // debugger if (to.path == '/login' || localStorage.getItem("token")) { next() } else { alert("尚未登錄,請先登錄") return next("/login") } })
-
-
路由 router/index.js
-
import Vue from 'vue' import Router from 'vue-router' import Home from "../components/layout/Home"; Vue.use(Router) const page = name => () => import('@/views/' + name) export default new Router({ mode: 'history', routes: [ {path: '/login', component: page('Login'), name: '登錄'}, { path: '/', component: index, name: 'index', children: [ {path: '/test', component: page('test/Test'), name: '測試頁面'}, {path: '/usermanage', component: page('user-manage/UserManage'), name: '用戶模塊'}, ] }, ] }) import VueRouter from 'vue-router' import index from "../components/index"; //import HelloWorld from '@/components/HelloWorld' const originalPush = VueRouter.prototype.push VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => err) }
-
-