接前面二,下面咱們實現右鍵菜單、http通訊、路由。html
本系列教程是用Vue.js + Nuxt.js + Element + Vuex + 開源js繪圖庫,打造一個屬於本身的在線繪圖軟件,最終效果:topology.le5le.com 。若是你以爲好,歡迎給文章和開源庫點贊,讓咱們更有動力去作好!vue
本系列教程源碼地址:Githubnode
右鍵菜單原理很簡單:自定義html的oncontextmenu事件:ios
<div id="topology-canvas" class="full" @contextmenu="onContextMenu($event)"></div>
複製代碼
屏蔽默認右鍵菜單事件,計算右鍵鼠標位置,彈出一個咱們本身的div自定義菜單便可git
onContextMenu(event) {
event.preventDefault()
event.stopPropagation()
if (event.clientY + 360 < document.body.clientHeight) {
this.contextmenu = {
left: event.clientX + 'px',
top: event.clientY + 'px'
}
} else {
this.contextmenu = {
left: event.clientX + 'px',
bottom: document.body.clientHeight - event.clientY + 'px'
}
}
}
複製代碼
<div class="context-menu" v-if="contextmenu.left" :style="this.contextmenu">
<ul>
<li>菜單一</li>
<li>菜單二</li>
<li>菜單三</li>
</ul>
</div>
複製代碼
在本項目中,封裝了一個右鍵菜單組件「CanvasContextMenu」,經過父組件,傳遞canvas實例和選中的屬性數據github
props: {
canvas: {
type: Object,
require: true
},
props: {
type: Object,
require: true
}
}
複製代碼
其中,屬性props含義爲:vuex
props: {
node: null, // 選中節點
line: null, // 選中連線
nodes: null, // 選中多個節點
multi: false, // 選中多個節點/連線
locked: false // 選中對象是否被鎖定
}
複製代碼
而後,咱們根據菜單事件和屬性props來調用canvas的相應接口函數,參考開發文檔element-ui
這裏,咱們不去從零寫個後端服務,直接採用topology.le5le.com線上接口服務。canvas
首先,咱們須要給nuxt.config.js添加http代理配置,這樣開發環境下的http請求,自動代理轉發給topology.le5le.com,獲取到真實數據。axios
axios: {
proxy: true
},
proxy: {
'/api/': 'http://topology.le5le.com/',
'/image/': 'http://topology.le5le.com/'
},
複製代碼
其中,proxy的含義是指:全部/api/、/image/開頭的請求,自動轉發給http://topology.le5le.com/ ,其餘的不轉發。 一般,咱們經過前綴/api/表示這是後端接口請求,而不是靜態資源請求;/image/表示靜態資源圖片請求。
因爲這裏,暫時沒有多頁面共享用戶信息,所以,咱們直接在layouts/default的頂部導航欄和data裏添加用戶數據
data() {
return {
about: false,
license: false,
joinin: false,
lineNames: ['curve', 'polyline', 'line'],
arrowTypes: [
'',
'triangleSolid',
'triangle',
'diamondSolid',
'diamond',
'circleSolid',
'circle',
'line',
'lineUp',
'lineDown'
],
user: null
}
}
<el-submenu index="user" v-if="user">
<template slot="title">
<el-avatar
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
:size="24"
></el-avatar>
{{user.username}}
</template>
<el-menu-item @click="onSignOut">退出</el-menu-item>
</el-submenu>
<el-menu-item v-if="!user">
<a @click="onLogin">註冊 / 登陸</a>
</el-menu-item>
複製代碼
大型項目,可能須要使用vuex去保存用戶數據
這裏,咱們直接省略登陸頁面,直接跳轉到線上登陸頁面account.le5le.com,共享登陸狀態。
凡是le5le.com的子域名,經過共享cookie中的token來共享le5le.com的登陸狀態。首先,咱們修改本地電腦的host文件,新增一條local.le5le.com子域名,映射到本地電腦:
127.0.0.1 local.le5le.com
複製代碼
如何修改host文件,請google。
而後,咱們把 http://localhost:3000/ 換成 local.le5le.com:3000/ 去在瀏覽器中打開咱們的開發頁面,這時,咱們就能夠點擊右上角「登陸/註冊」,去登陸。
在le5le.com上,是使用jwt的方式去用戶認證的。jwt的token值存儲在cookie中,方便子域名共享登陸。而後每一個http請求headers裏面加上Authorization: token值,後端服務就能夠認證用戶身份。
在第一次打開網頁初始化時,只需在請求後端服務/api/user/profile獲取用戶便可。當接口/api/user/profile返回用戶數據,表示用戶已登陸;當返回401表示未登陸。這裏,咱們先判斷了是否存在cookie下的token在請求用戶接口。參考default.vue:
async getUser() {
if (this.$cookies.get('token')) {
this.user = await this.$axios.$get('/api/user/profile')
}
},
複製代碼
async和await是成對出現的。函數名前面加async,函數裏面就可使用await表示必須等待await後面的函數執行完獲得返回結果,才繼續執行後面的代碼。一般用於等待異步請求結果,避免回調。即便沒有異步也是能夠的。
爲了每次請求自動把cookie裏面的token添加到headers裏面,咱們須要按照下面操做,寫一個http請求的攔截器。
http攔截器的做用時,每次請求和數據返回時,自動幫咱們處理一些全局公用操做。好比這裏的身份認證token添加。
2.2.1 新建一個plugins/axios.js插件文件 經過axios插件的方式實現http攔截器。
export default function({ $axios, app, redirect }) {
// 設置token,添加Authorization到headers
$axios.setToken(app.$cookies.get('token'))
$axios.onResponse(response => {
// 統一錯誤處理。若是發現error字段,則發送一個notice/error錯誤消息。在default.vue監聽並彈出右上角錯誤提示框
if (response.error) {
app.store.commit('notice/error', { text: response.error })
}
})
$axios.onError(error => {
// 經過code狀態碼判斷接口是否出錯。請自行google學習http狀態碼
const code = parseInt(error.response && error.response.status)
if (code === 401) {
// 須要登陸
app.store.commit('notice/error', {
text: '請先登陸!'
})
} else if (code === 403) {
// 無權限訪問
redirect('/')
} else if (code === 500) {
app.store.commit('notice/error', {
text: error.response.error || '服務錯誤,請稍後重試!'
})
}
})
}
複製代碼
2.2.2 nuxt.config.js中配置加載axios插件
plugins: ['@/plugins/element-ui', '@/plugins/axios'],
複製代碼
2.2.3 添加cookie插件 由於咱們須要讀取cookie,全部安裝一個cookie插件,方便使用。
yarn add cookie-universal-nuxt --save
複製代碼
nuxt.config.js中
modules: [
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
'cookie-universal-nuxt'
],
複製代碼
而後,能夠直接在咱們的plugins/axios.js和(default).vue中使用了。
nuxt.js不須要去寫router.js,約定pages下的vue文件就是路由。比較省事。 咱們添加一個新的index.vue首頁,把原index.vue改爲workspace.vue。 新index.vue:
<template>
<div class="page-list">
<div>
<div class="nav">
<label>熱門圖文</label>
</div>
<div class="flex wrap">
<div
class="topo"
v-for="(item, index) of data.list"
:key="index"
:title="item.desc"
@click="onOpen(item)"
>
<div class="image">
<img :src="item.image" />
</div>
<div class="ph15 pv10">
<div class="title line one" :title="item.name">{{ item.name }}</div>
<div class="desc line two mt5" :title="item.desc">{{ item.desc }}</div>
<div class="flex mt5">
<div class="full flex middle">
<el-avatar
src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"
:size="24"
></el-avatar>
<span class="ml5">{{ item.username }}</span>
</div>
<div>
<span class="hover pointer mr15" title="贊">
<i
class="iconfont"
:class="{'iconfont icon-appreciate':!item.stared, 'iconfont icon-appreciatefill':item.stared}"
></i>
<span class="ml5">{{ item.star || 0 }}</span>
</span>
<span class="hover pointer" title="收藏">
<i
class="iconfont"
:class="{'iconfont icon-like':!item.favorited, 'iconfont icon-likefill':item.favorited}"
></i>
<span class="ml5">{{ item.hot || 0 }}</span>
</span>
</div>
</div>
</div>
</div>
</div>
<div>
<el-pagination
@current-change="getList"
:current-page="search.pageIndex"
:page-size="8"
layout=" prev, pager, next, jumper, total"
:total="data.count"
></el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
data: {
list: [],
count: 0
},
search: {
pageIndex: 1,
pageCount: 8
}
}
},
created() {
this.getList()
},
methods: {
async getList() {
this.data = await this.$axios.$get(
`/api/topologies?pageIndex=${this.search.pageIndex}&pageCount=${this.search.pageCount}`
)
},
onOpen(item) {
this.$router.push({ path: '/workspace', query: { id: item.id } })
}
}
}
</script>
複製代碼
index.vue 主要包含:1. getList獲取首頁列表數據;2. this.$router.push({ path: '/workspace', query: { id: item.id } }) 打開具體頁面
路由詳情:zh.nuxtjs.org/guide/routi…
自此,一個麻雀雖小五臟俱全的小項目就完成了,包含:框架搭建、插件、vuex、身份認證、http通訊、路由等功能。
整個項目功能細節還不完善,歡迎你們提pr:
完整細節可參考:topology.le5le.com/ ,開發文檔 。可加入貢獻者名單哦!也歡迎加羣交流討論:
經過GitHub的pr方式: 0. 閱讀開發文檔,瞭解相關屬性。