【前端vue進階實戰】:從零打造一個流程圖、拓撲圖項目【Nuxt.js + Element + Vuex】 (一)

本系列教程是用Vue.js + Nuxt.js + Element + Vuex + [開源js繪圖庫](https://juejin.im/post/5d6c88726fb9a06b0e54ab35),打造一個屬於自己的在線繪圖軟件,最終效果:http://topology.le5le.com 。如果你覺得好,歡迎給文章和[開源庫](https://github.com/le5le-com/topology)點贊,讓我們更有動力去做好!

本系列教程源碼地址:[Github](https://github.com/le5le-com/topology-vue)

# 一、創建項目框架
## 1. 使用Nuxt.js嚮導創建項目
```
yarn create nuxt-app topology-vue
// 注意在後面提示中,上移下移,按空格選中 Element
```

選擇Element後,在plugins文件夾下會自帶添加Element的插件配置

![file](https://graph.baidu.com/resource/212e75223e1a379e8cfc401574326390.png)

完成後,在nuxt.config.js中配置head相關信息,主要有兩個阿里字體文件:
左側工具欄字體文件:
//at.alicdn.com/t/font_1113798_0532l8oa6jqp.css 

右側屬性字體圖標:
//at.alicdn.com/t/font_1331132_5lvbai88wkb.css

```
head: {
    title: '樂吾樂 Topology - 開源免費繪圖工具',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content:
          '一個基於typescript + canvas的好用開源繪圖工具和繪圖引擎。易集成到自己的前端項目、還可以方便自定義圖形庫,支持微服務架構圖、流程圖、時序圖、活動圖、類圖等'
      }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      {
        rel: 'stylesheet',
        href: '//at.alicdn.com/t/font_1113798_0532l8oa6jqp.css'
      },
      {
        rel: 'stylesheet',
        href: '//at.alicdn.com/t/font_1331132_5lvbai88wkb.css'
      }
    ]
  },
```

## 2. 添加SCSS支持
2.1 安裝scss的依賴包
```
yarn add node-sass sass-loader  -D 
```

2.2 給style標籤加上lang="scss"標記
```
<style lang="scss">
.page {
  width: 100%;
  height: 100%;
}
</style>
```

## 3. 添加一個全局公用css
3.1 在asstes/css文件夾下新建一個base.scss公用全局樣式文件
![file](https://graph.baidu.com/resource/2126d6d92e5423f19acd301574326475.png)

3.2 導入
在layouts/default.vue的script腳本中導入:
```
import '~/assets/css/base.scss'
```

# 二、網頁佈局
## 1. 頂部導航欄
修改layouts/default.vue爲導航欄 + body兩部分
![file](https://graph.baidu.com/resource/2120989f8e740c865aa8c01574328255.png)

其中:<nuxt /> 爲Nuxt.js框架中對應頁面路由的視圖部分。

## 2. 修改首頁爲左中右三欄
修改pages/index.vue爲左中右三欄佈局
![file](https://graph.baidu.com/resource/212c67df43aede1a834a301574328511.png)

# 三、創建畫布
## 1. 下載topology依賴包
```
yarn add  topology-core topology-class-diagram topology-activity-diagram topology-flow-diagram topology-sequence-diagram -D 
```

其中,topology-core爲核心庫引擎,其他的爲圖形庫。具體參考:[開發文檔](https://www.yuque.com/alsmile/topology/installation)

## 2. 註冊圖形庫
我們單獨寫個pages/canvas.server.js服務,用來提供topology相關服務
![file](https://graph.baidu.com/resource/212519c319cb2df57e37001574334177.png)

這裏主要提供註冊和左側工具欄數據。

## 3. 加載圖形庫
**3.1 準備canvas相關數據**
```
data() {
    return {
          // 左側工具欄
      tools: Tools,
            // 圖形庫
      canvas: {},
            // 圖形庫選項:https://www.yuque.com/alsmile/topology/canvas#hOupV
      canvasOptions: {
        rotateCursor: '/img/rotate.cur'
      },
            // 右側屬性欄數據
      props: {
        node: null,
        line: null,
        multi: false
      }
    }
  }
```

**3.2 註冊圖形庫**
```
created() {
    canvasRegister()
}
```

**3.3 在父節點已經渲染後,new創建畫布**
```
mounted() {
    this.canvasOptions.on = this.onMessage
    this.canvas = new Topology('topology-canvas', this.canvasOptions)
}
```

其中,onMessage 表示接受畫布的消息回調函數

**3.4 左側工具欄支持鼠標拖放**
```
<a
            v-for="(btn, i) in item.children"
            :key="i"
            :title="btn.name"
            :draggable="btn.data"
            @dragstart="onDrag($event, btn)"
          >
            <i :class="`iconfont ${btn.icon}`"></i>
          </a>
```

```
methods: {
    onDrag(event, node) {
      event.dataTransfer.setData('Text', JSON.stringify(node.data))
    }
  }
```

只需要給拖放數據設置節點格式的字符串即可(畫布自帶支持拖放接收處理),節點數據格式文檔:https://www.yuque.com/alsmile/topology/node

**3.5 右側屬性欄**

- 3.5.1 自定義屬性欄組件
在components下創建CanvasProps.vue
```
<template>
  <div>
      <!-- 選中爲空 -->
    <div v-if="!props.node && !props.line && !props.multi">
      <div class="title">歡迎使用le5le-topology!</div>
      <div class="group">
        <a class="star" href="https://github.com/le5le-com/topology" target="_blank">喜歡,點擊這裏打個star吧</a>
        <a href="https://www.yuque.com/alsmile/topology" target="_blank">使用教程</a>
        <br />
        <a
          href="http://topology.le5le.com/assets/img/topology_wechat.jpg?t=1"
          target="_blank"
        >微信交流羣(大羣)</a>
        <br />
        <a href="http://topology.le5le.com/assets/img/topology_wechat2.jpg" target="_blank">微信交流羣2</a>
        <br />
        <a href="https://www.yuque.com/alsmile/topology/faq#EVbCgt" target="_blank">聯繫我們</a>
      </div>
      <div class="title">[Todo] 未來規劃</div>
      <ul class="group">
        <li>Github issues</li>
        <li>React demo</li>
        <li>Vue3 demo</li>
        <li>系列教程</li>
      </ul>
      <div class="bottom">
        <div class="title">小提示</div>
        <ul class="group">
          <li>方向鍵:控制節點移動5個像素</li>
          <li>Ctrl + 方向鍵:控制節點移動1個像素</li>
          <li>Ctrl + 鼠標移動:移動整個畫布</li>
          <li>Ctrl + 鼠標滾輪:縮放</li>
          <li>添加或選中節點,右側屬性支持上傳各種圖片哦</li>
        </ul>
      </div>
    </div>
        <!-- 選中節點 -->
    <div v-if="props.node">
      <div class="title">位置和大小</div>
      <div class="items">
        <div class="flex grid">
          <div>X(px)</div>
          <div class="ml5">Y(px)</div>
        </div>
        <div class="flex grid">
          <div>
            <el-input-number
              v-model="props.node.rect.x"
              controls-position="right"
              @change="onChange"
            ></el-input-number>
          </div>
          <div class="ml5">
            <el-input-number
              v-model="props.node.rect.y"
              controls-position="right"
              @change="onChange"
            ></el-input-number>
          </div>
        </div>
      </div>
      <div class="items">
        <div class="flex grid">
          <div>寬(px)</div>
          <div class="ml5">高(px)</div>
        </div>
        <div class="flex grid">
          <div>
            <el-input-number
              v-model="props.node.rect.width"
              controls-position="right"
              @change="onChange"
            ></el-input-number>
          </div>
          <div class="ml5">
            <el-input-number
              v-model="props.node.rect.height"
              controls-position="right"
              @change="onChange"
            ></el-input-number>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script >
export default {
  data() {
    return {}
  },
  props: {
    props: {
      type: Object,
      require: true
    }
  },
  methods: {
    onChange(value) {
      this.$emit('change', this.props.node)
    }
  }
}
</script>
```

其中,props.node、line、multi分別表示是否選中節點、連線、多個對象。
這裏我們暫時沒有用到vuex(後面教程介紹),直接使用原生的雙向綁定更簡單。用$emit通知父組件屬性改變事件。

相關屬性值,參數API文檔:https://www.yuque.com/alsmile/topology/node

- 3.5.2 引用右側屬性組件
```
<div class="props">
      <CanvasProps :props.sync="props" @change="onUpdateProps"></CanvasProps>
</div>
```
同樣,我們利用.sync關鍵字使用雙向綁定,並接收chang事件,反饋給畫布組件:
```
onUpdateProps(node) {
      // 如果是node屬性改變,需要傳入node,重新計算node相關屬性值
      // 如果是line屬性改變,無需傳參
      this.canvas.updateProps(node)
}
```

# 其他
自此,一個簡單的繪圖項目就完成了,後續功能完善待續。

但,但,但...右側屬性欄,希望大家根據[開發文檔](https://www.yuque.com/alsmile/topology)去參與完善,展示自己舞臺的機會到了,可加入貢獻者名單哦!不清楚的,歡迎聯繫管理員:(微信)alsmile123,或加羣:![topology技術討論羣2](http://topology.le5le.com/assets/img/topology_wechat2.jpg)

## 如何貢獻
通過GitHub的pr方式:
0. 閱讀[開發文檔](https://www.yuque.com/alsmile/topology/node),瞭解相關屬性。
1. fork倉庫到自己名下
2. 本地修改並提交到自己的git倉庫
3. 在自己的fork倉庫找到 “Pull request” 按鈕,提交
![file](https://graph.baidu.com/resource/2126e2b651dac023e4a7301573651414.png)


**開源項目不易,歡迎大家一起參與,給【文章、GitHub開源庫】點星點贊,或資助服務器:**  
![file](https://graph.baidu.com/resource/2128226662beefae502c401573651841.png)
 

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