我使用的是 vue-cli
初始化專案,命令如下:
npm i -g vue-cli
mkdir my-project && cd my-project
vue init webpack
修改 package.json
檔案:
...
"dependencies": {
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"element-ui": "^2.0.7", // element-ui
"axios": "^0.17.1" // http 請求庫
}
...
之後執行 npm install
進行安裝依賴,如果安裝速度有點慢的話,可以試一下 cnpm
,具體安裝和用法自行查詢。
簡單介紹下專案的目錄結構:
├─build // 構建配置
├─config // 配置檔案
├─src // vue 開發原始檔目錄
├────assets // css/js 檔案
├────components // vue 元件
├────router // 路由
├────App.vue // 啟動元件
├────main.js // 入口檔案
├─static // 靜態檔案目錄
├─test // 測試目錄
之後在專案根目錄執行 npm run dev
,開啟瀏覽器輸入 http://localhost:8080
就可以檢視了。
- [ ] 登入頁面,登入,退出功能
- [ ] 首頁,呼叫介面渲染列表
路由使用的是 vue-router
,具體用法可參考 官方文件
我們這裡需要兩個路由:
src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/Index'
import Login from '@/components/Login'
Vue.use(Router)
const routers = new Router({
routes: [
{
path: '/index',
name: 'index',
component: Index
},
{
path: '/login',
name: 'login',
component: Login
}
]
})
routers.beforeEach((to, from, next) => {
if (to.name !== 'login' && !localStorage.getItem('token')) {
next({path: 'login'})
} else {
next()
}
})
export default routers
src/components/Login.vue
<template>
<div class="login">
<el-form name="aa" :inline="true" label-position="right" label-width="80px">
<el-form-item label="使用者名稱">
<el-input v-model="user.name"></el-input>
</el-form-item>
<el-form-item label="密碼">
<el-input type="password" v-model="user.password"></el-input>
</el-form-item>
<el-form-item label=" ">
<el-button type="primary" @click="login()">登入</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import $http from '@/api/'
import config from '@/config'
export default {
data () {
return {
user: {
name: '',
password: ''
}
}
},
mounted: function () {
var token = localStorage.getItem('token')
if (token) {
this.$router.push('/index')
}
},
methods: {
login: function () {
var data = {
grant_type: 'password',
client_id: config.oauth_client_id,
client_secret: config.oauth_secret,
username: this.user.name,
password: this.user.password
}
var _this = this
$http.login(data).then(function (res) {
if (res.status === 200) {
$http.setToken(res.data.access_token)
_this.$message({
showClose: false,
message: '登入成功',
type: 'success'
})
_this.$router.push('/index')
} else {
_this.$message({
showClose: false,
message: '登入失敗',
type: 'error'
})
}
})
}
}
}
</script>
<style>
.login{
width: 300px;
margin: 100px auto;
background-color: #ffffff;
padding: 30px 30px 5px;
border-radius: 5px;
}
</style>
src/components/Index.vue
<template>
<div class="main">
<el-table
stripe
v-loading="loading"
element-loading-background="#dddddd"
:data="tableData"
style="width: 100%">
<el-table-column
prop="id"
label="ID">
</el-table-column>
<el-table-column
prop="name"
label="名稱">
</el-table-column>
</el-table>
<el-pagination
background
layout="prev, pager, next"
:total="total"
class="page"
@current-change="pageList">
</el-pagination>
</div>
</template>
<script>
import $http from '@/api/'
export default {
data () {
return {
tableData: [],
total: 0,
loading: false
}
},
mounted: function () {
this.getList()
},
methods: {
pageList: function (page) {
this.search.page = page
this.getList()
},
getList: function () {
var _this = this
_this.loading = true
$http.index().then(function (res) {
if (res.status === 200) {
_this.tableData = res.data.data.lists
_this.total = res.data.data.total
}
_this.loading = false
})
}
}
}
</script>
src/App.vue
<template>
<div id="app">
<el-row v-if="token">
<menus class="left-menu">
<h3 class="logo"><a href="/">Admin</a></h3>
</menus>
<el-col :span="21" :gutter="0" :offset="3">
<el-breadcrumb separator-class="el-icon-arrow-right" class="breadcrumb">
<el-breadcrumb-item :to="{ path: '/' }">首頁</el-breadcrumb-item>
<el-breadcrumb-item class="active">列表</el-breadcrumb-item>
</el-breadcrumb>
<el-dropdown @command="operate" class="header">
<img src="/static/image/head.jpg" />
<el-dropdown-menu slot="dropdown" :click="true">
<el-dropdown-item command="/user/profile">基本資料</el-dropdown-item>
<el-dropdown-item command="/logout">安全退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<router-view/>
</el-col>
<el-col :span="21" :gutter="0" :offset="3" class="footer">Copyright © 2017 Flyerboy All Rights Reserved</el-col>
</el-row>
<router-view v-if="!token" />
</div>
</template>
<script>
import Menus from '@/components/Menu'
export default {
name: 'App',
data () {
return {
token: false
}
},
mounted: function () {
this.token = localStorage.getItem('token') ? true : false
},
watch: {
'$route.path': function ($newVal, $oldVal) {
this.token = localStorage.getItem('token') ? true : false
}
},
methods: {
operate: function (command) {
if (command === '/logout') {
localStorage.removeItem('token')
this.$router.push('login')
} else {
this.$router.push(command)
}
}
},
components: {
Menus
}
}
</script>
<style>
body{
margin: 0;
padding: 0;
background-color: #eeeeee;
}
.header{
position: absolute;
top: 5px;
right: 20px;
}
.header img{
width: 38px;
height: 38px;
border-radius: 20px;
border: 1px solid #aaaaaa;
}
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.main{
padding: 20px;
min-height: 600px;
margin-bottom: 20px;
}
.main table{
background: #ffffff;
}
.left-menu{
background-color: #33374B;
}
.logo{
padding: 20px 0 15px 20px;
font-size: 24px;
border-bottom: 2px solid #3a8ee6;
}
.logo a{
color: #ffffff;
text-decoration: none;
}
.left-menu .el-menu{
border-right: 0;
}
.breadcrumb{
line-height: 40px;
padding: 5px 20px;
background: #ffffff;
}
.breadcrumb span{
color: #069;
font-weight: normal;
}
.breadcrumb .active{
color: #aaaaaa;
}
.page{
margin: 20px 0 0;
margin-left: -10px;
}
.page .el-pager li.number{
background-color: #ffffff;
}
.el-submenu .el-menu-item{
padding-left: 60px !important;
}
.footer{
position: fixed;
bottom: 0;
right: 0;
font-size: 12px;
color: #888888;
padding: 15px 20px;
text-align: center;
background-color: #ffffff;
margin-top: 40px;
}
</style>
src/api/index.js
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:8000/'
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token')
export default {
setToken: function (token) {
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
},
login: function (param) {
return axios.post('oauth/token', param)
},
index: function (params) {
return axios.get('api/user/list', {
params: params
})
}
}
src/config.js 這裡配置登入 oauth 需要的 client_id 和 secret
export default {
oauth_client_id: 2,
oauth_secret: ''
}
src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
主要用到兩個介面,一個是 api/oauth/token
登入獲取 token 介面,一個獲取列表 api/user/list
。
第一個介面是用到 laravel oauth,第二個介面直接是一個簡單的查詢使用者列表介面,詳細講會在下一篇文章中講述。
本作品採用《CC 協議》,轉載必須註明作者和本文連結