回顧
作者用心寫作,請動動你可愛的小手點亮大拇指
。你的鼓勵是作者繼續創作的動力…
前端的學習,不能僅僅依靠知識點的學習,實戰項目的操作可以幫助我們整理知識點以及提高編程能力,更有助於學習和實踐,最重要的是提高自己的項目經驗,對於找工作而言有着大大的幫助。
閱讀本篇文章之前,可以先看看上一篇分享的內容,主要講大數據可視化的由來,與前端的淵源,主題風格設計,選擇比較流行的可視化第三方庫。
一個基於Vue前端框架和第三方圖表庫Echarts構建的可視化大數據平臺,通過vue項目構建、指令的靈活運用、組件封裝、組件之間通信,使內部圖表組件庫可實現自由替換和組合。以及一些功能模塊的設計及代碼實現。
老規矩先上效果圖(可視化酷屏展示公司品牌),後面會講這個實例。
線上體驗:https://jackchen0120.github.io/vueDataV/#/brand
下面接着繼續分享上一篇未講完的內容。
自定義全局模態框
先看效果圖:
自定義模態框已註冊全局小組件在/components/modal目錄文件,代碼如下(含註解):
<template>
<transition name="fade">
<div class="modal-backdrop" v-if="visible">
<div class="modal">
<div class="modal-header">
{{ title }}
<i class="iconfont icon-close close" @click="close"></i>
</div>
<div class="modal-body">
{{ content }}
</div>
<div class="modal-footer">
<button type="button" class="btn-close" @click="close" v-if="showCancle">
{{cancleText ? cancleText : '取消'}}
</button>
<button type="button" class="btn-confirm" @click="confirm">
{{confirmText ? confirmText : '確定'}}
</button>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
name: 'Modal',
props: {
// modal標題
title: {
type: String,
default: '提示'
},
// modal內容
content: {
type: String,
default: ''
},
// 是否顯示
visible: {
type: Boolean,
default: false
},
// 是否顯示取消按鈕
showCancle: {
type: Boolean,
default: true
},
// 確認按鈕文字
confirmText: {
type: String,
default: '確認'
},
// 取消按鈕文字
cancleText: {
type: String,
default: '取消'
}
},
watch: {
visible (curVal) {
// 監聽visible值的變化
console.log(curVal)
}
},
methods: {
// 關閉按鈕事件
close() {
this.$emit('update:visible', false);
},
// 確定按鈕事件
confirm() {
this.close();
this.$emit('confirm');
}
}
}
</script>
在components/index.js目錄文件中註冊全局組件,如下圖:
完整代碼如下:
// 引入自定義全局模態框組件
import modal from './modal'
const components = {
modal,
};
// install 是默認的方法。當外界在 Vue.use() 這個組件的時候,就會調用本身的 install 方法,同時傳一個 Vue 這個類的參數。
const install = (Vue = {}) => {
if (install.installed) return;
Object.keys(components).forEach(component => {
Vue.component(components[component].name, components[component]);
});
install.installed = true;
};
install.installed = false;
if (typeof window !== "undefined" && window.Vue) {
install(window.Vue);
install.installed = true;
}
// 定義組件庫和install對象
const Vcomp = {
...components,
install
};
// 導出
export default Vcomp
在main.js中全局引用,如下圖:
可在任意頁面調用,代碼如下:
<template>
<div class="page">
<modal
title="提示"
:content="modalContent"
:visible.sync="visible"
@confirm="confirm">
</modal>
</div>
</template>
export default {
data() {
return {
visible: true, // 顯示模態框
modalContent: '這是一段自定義模態框消息'
}
},
methods: {
confirm() {
this.visible = false;
console.log('點擊確定')
}
}
}
參數名 | 類型 | 說明 |
---|---|---|
visible | Boolean | 是否顯示,默認false |
title | String | 標題 |
content | String | 內容 |
confirmText | String | 確認按鈕文字,默認“確認” |
cancleText | String | 取消按鈕文字,默認“取消” |
showCancle | Boolean | 是否顯示,默認true |
update:visible | Boolean | 更新visible, 使用:visible.sync 實現動態綁定 |
數字滾動組件
推薦一款簡單好用的數字滾動組件,vue-count-to
是一個無依賴,輕量級的vue組件,可以自行覆蓋easingFn。你可以設置 startVal 和 endVal,它會自動判斷計數或倒計時。支持vue-ssr,vue-countTo參考於countUp.js。
- npm安裝依賴
npm install -D vue-count-to
- 示例代碼:
<template>
<countTo :startVal='startVal' :endVal='endVal' :duration='3000'></countTo>
</template>
<script>
import countTo from 'vue-count-to';
export default {
components: { countTo },
data () {
return {
startVal: 0,
endVal: 2020
}
}
}
</script>
- 選項:
屬性 | 描述 | 數據類型 | 默認值 |
---|---|---|---|
startVal | 開始值 | Number | 0 |
endVal | 結束值 | Number | 2020 |
duration | 持續時間,以毫秒爲單位 | Number | 3000 |
autoplay | 自動播放 | Boolean | true |
decimals | 要顯示的小數位數 | Number | 0 |
decimal | 十進制分割 | String | .(點) |
separator | 分隔符 | String | ,(逗號) |
prefix | 前綴 | String | ‘’(空字符串) |
suffix | 後綴 | String | ‘’(空字符串) |
useEasing | 使用緩和功能 | Boolean | true |
easingFn | 緩和回調 | Function | — |
*注意:當autoplay:true時,它將在startVal或endVal更改時自動啓動
- 功能:
函數名 | 描述 |
---|---|
mountedCallback | 掛載以後返回回調 |
start | 開始計數 |
pause | 暫停計數 |
reset | 重置countTo |
首頁動態列表組件顯示的數據,就引用了數字滾動特效,如下圖:
代碼如下圖:
如需查看完整源代碼請移步到作者的github倉庫
講講炫酷展示公司品牌實例
功能模塊
- 天氣和當前日期
- 自定義詞雲圖
- 模擬飛機航線動效
- 自動切換tab選項卡
- 柱狀圖、餅圖、折線圖、南丁格玫瑰圖
技術棧
- 基於 flexible.js + rem 智能大屏適配
之前首頁大屏佈局採用的是絕對定位,加上整體屏幕縮放進行適配(簡單粗暴,不是很優雅
)。
現在推薦一種智能大屏適配方式,選用flexible.js是淘寶移動端自適應解決方案,源碼含註解如下:
// 首先是一個立即執行函數,執行時傳入的參數是window和document
(function flexible(window, document) {
// 返回文檔的root元素
var docEl = document.documentElement;
// 獲取設備的dpr,即當前設置下物理像素與虛擬像素的比值
var dpr = window.devicePixelRatio || 1;
// 設置默認字體大小,默認的字體大小繼承自body
function setBodyFontSize() {
if (document.body) {
// 調整body標籤的fontSize,fontSize = (12 * dpr) + 'px'
document.body.style.fontSize = 12 * dpr + 'px';
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize);
}
}
setBodyFontSize();
// set 1rem = viewWidth / 24
function setRemUnit() {
// 設置root元素的fontSize = 其clientWidth / 24 + 'px'
var rem = docEl.clientWidth / 24;
docEl.style.fontSize = rem + 'px';
}
setRemUnit();
// 當頁面展示或重新設置大小的時候,觸發重新
window.addEventListener('resize', setRemUnit);
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
setRemUnit();
}
});
// 檢測0.5px的支持,支持則root元素的class中有hairlines
if (dpr >= 2) {
var fakeBody = document.createElement('body');
var testElement = document.createElement('div');
testElement.style.border = '.5px solid transparent';
fakeBody.appendChild(testElement);
docEl.appendChild(fakeBody);
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines');
}
docEl.removeChild(fakeBody);
}
})(window, document);
設計稿尺寸是1920px*1080px,所以將屏幕分成24等份。
- sublime text 3 cssrem插件
// 先下載插件到本地
git clone https://github.com/flashlizi/cssrem
進入packages目錄:Sublime Text -> Preferences -> Browse Packages… 如下圖:
將下載到本地的cssrem目錄複製到packges目錄裏,如下圖:
然後重啓Sublime Text,參數配置如下圖:
如果小夥伴使用的vscode編輯器,也可以安裝此插件,打開擴展,搜索cssrem,點擊安裝,如下圖:
配置設置,如下圖:
改完後重啓,插件效果如圖:
- Flex 佈局
Flex是Flexible Box的縮寫,意爲”彈性佈局”,用來爲盒狀模型提供最大的靈活性。可以簡便、完整、響應式地實現各種頁面佈局。這裏推薦阮一峯老師的Flex佈局教程。
動手之前,先來分析一下整個頁面設計佈局,整體佈局分爲上(頭部模塊)和下(主體模塊),主體模塊又分爲左中右三部分。主體中間又分爲上(數字滾動模塊)和下(地圖模塊)。
頭部佈局樣式採用的是定位position,主體模塊column列容器,分三列,佔比 3 : 5 : 3。主體代碼如下:
<section class="mainbox">
<div class="item left">
flex: 3;
</div>
<div class="item center">
flex: 5;
</div>
<div class="item right">
flex: 3;
</div>
</section>
.mainbox {
min-width: 1024px;
max-width: 1920px;
padding: 0.125rem 0.125rem 0;
display: flex;
.item {
flex: 3;
&.center {
flex: 5;
margin: 0 0.125rem 0.1rem;
overflow: hidden;
}
}
}
全屏設置背景圖及頭部佈局樣式,可以直接在/src/views/Brand.vue目錄文件查看源代碼。
補充說明頭部有展示天氣和當前時間,天氣數據實時展示,通過axios的get方法調用第三方免費天氣API接口,並且設置每小時獲取一次最新數據。代碼實現如下:
mounted() {
this.getWeather();
this.timer = setInterval(() => {
this.getWeather();
}, 1000 * 60 * 60)
},
methods: {
getWeather() { // 第三方天氣api接口
axios.get('https://www.tianqiapi.com/api/', {
params: {
appid: '26148275',
appsecret: '2id6H48Y',
version: 'v6'
}
}).then(res => {
if (res.data) {
if (res.data.wea_img == 'xue') {
this.imgSrc = require('../assets/img/brand/xue.png');
} else if (res.data.wea_img == 'yin') {
this.imgSrc = require('../assets/img/brand/yin.png');
} else if (res.data.wea_img == 'yu' || res.data.wea_img == 'bingbao') {
this.imgSrc = require('../assets/img/brand/yu.png');
} else if (res.data.wea_img == 'yun') {
this.imgSrc = require('../assets/img/brand/yun.png');
} else if (res.data.wea_img == 'wu') {
this.imgSrc = require('../assets/img/brand/wu.png');
} else if (res.data.wea_img == 'shachen') {
this.imgSrc = require('../assets/img/brand/shachen.png');
} else if (res.data.wea_img == 'lei') {
this.imgSrc = require('../assets/img/brand/lei.png');
} else {
this.imgSrc = require('../assets/img/brand/qing.png');
}
this.weatcherData = res.data;
}
}).catch(err => {
console.log(err)
})
}
}
當前時間代碼實現如下:
mounted() {
this.nowTimes();
},
methods: {
timeFormate(timeStamp) { //顯示當前時間
let newDate = new Date(timeStamp);
let year = newDate.getFullYear();
let month = newDate.getMonth() + 1 < 10 ? '0' + (newDate.getMonth() + 1) : newDate.getMonth() + 1;
let date = newDate.getDate() < 10 ? '0' + newDate.getDate() : newDate.getDate();
let hh = newDate.getHours() < 10 ? '0' + newDate.getHours() : newDate.getHours();
let mm = newDate.getMinutes() < 10 ? '0' + newDate.getMinutes() : newDate.getMinutes();
let ss = newDate.getSeconds() < 10 ? '0' + newDate.getSeconds() : newDate.getSeconds();
let week = newDate.getDay();
let weeks = ['日', '一', '二', '三', '四', '五', '六'];
let getWeek = '星期' + weeks[week];
this.week = getWeek;
this.date = year + '.' + month + '.' + date;
this.nowTime = hh + ':' + mm + ':' + ss;
},
nowTimes() {
this.timeFormate(new Date());
setInterval(this.nowTimes, 1000);
this.clear();
},
clear() {
clearInterval(this.nowTimes)
this.nowTimes = null;
},
}
- Echarts 圖表和地圖的基本使用
1)Echarts使用五部曲
- 本項目採用cdn引入echarts.js文件(圖表依賴這個js庫)
index.html引入cdn
vue.config.js配置webpack
- 準備一個具備大小的容器(生成的圖表會放入這個容器內)
<div class="chart" id="chart" style="width: 480px; height: 240px;"></div>
- 初始化echarts實例對象(實例化echarts對象)
let myChart = echarts.init(document.getElementById('chart'));
- 指定配置項和數據 option(根據具體需求修改配置選項)
let option = {
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
areaStyle: {},
smooth: true
}]
};
- 將配置項設置給echarts實例對象(讓echarts對象根據修改好的配置生效)
myChart.setOption(option);
// 讓圖表跟隨屏幕自適應
window.addEventListener("resize", () => {
myChart.resize();
});
2)瞭解echarts基礎配置
如需瞭解更多,請移步到Echarts官網查看相關文檔。
3)製作柱狀圖圖表
一般直接去echarts官網查找類似實例,適當分析,並且引入到頁面中,再根據需求定製圖表。官方實例地址:https://echarts.apache.org/examples/zh/index.html#chart-type-bar
比如上圖的效果是如何實現的呢?
作者悄悄地告訴你,其實有個很簡單的方法,直接在Echarts社區查找,因爲社區有很多活躍的Echarts使用者,經常貢獻一些非常棒的圖表示例。
本項目參考實例地址:https://gallery.echartsjs.com/editor.html?c=xgqdKhn5c,經過修改調整,最終呈現的效果如上圖。已封裝註冊全局小組件,源代碼在/src/components/companySummary/business.vue目錄文件,請自行查看。
4)Echarts map地圖使用
也是參考社區例子:模擬飛機航線動效
實現步驟:
- 首先下載引入中國地圖china.js文件(文件存放路徑:/src/assets/js/china.js)
- 其次使用社區實例的配置即可,修改圖例,標題,背景色,地圖放大比例等達到你想要的效果。
這個例子是擴展案例,大家以後可以多看看社區裏面的實例。
/* 約束屏幕尺寸 */
@media screen and (max-width: 1024px) {
html {
font-size: 42px !important;
}
}
@media screen and (min-width: 1920) {
html {
font-size: 80px !important;
}
}
5)自定義詞雲圖
先上效果圖
上圖效果,作者已封裝註冊全局小組件,源代碼在/src/components/companySummary/wordCloud.vue目錄文件,請自行查看。
首先下載echarts-wordcloud.min.js壓縮文件(存放路徑:/src/assets/js),並導入到wordCloud.vue模板文件中。代碼如下:
<template>
<div class="word-container">
<div class="chart" id="chart_right1"></div>
</div>
</template>
<script>
import '@/assets/js/echarts-wordcloud.min'
export default {
name: "wordCloud",
data() {
return {
timer: null
}
},
mounted() {
this.getEchartRight1();
this.timer = setInterval(() => {
this.getEchartRight1();
}, 5000)
},
methods: {
getEchartRight1() {
let myChart = echarts.init(document.getElementById('chart_right1'));
let option = {
// tooltip: {
// show: false
// },
series: [{
type: 'wordCloud',
gridSize: 1,
sizeRange: [12, 50],
rotationRange: [-90, 90],
rotationStep: 45,
shape: 'diamond',
width: '90%',
textPadding: 0,
autoSize: {
enable: true,
minSize: 6
},
textStyle: {
normal: {
textBorderColor: 'rgba(255,255,255,0.3)',
textBorderWidth: 1,
color: () => {
return 'rgb(' + [
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') + ')';
}
},
emphasis: {
fontSize: 20,
// shadowBlur: 10,
// shadowColor: 'rgba(255,255,255, .1)'
}
},
data: [{
name: '區塊鏈',
value: 810
}, {
name: '雲計算',
value: 520
},{
name: "人工智能",
value: 928
},{
name: "大數據",
value: 906
},{
name: "工業互聯網",
value: 825
},{
name: "醫療",
value: 514
},{
name: "質量溯源",
value: 486
},{
name: "政務",
value: 53
},{
name: "密碼學",
value: 927
},{
name: "金融行業",
value: 1308
},{
name: "供應鏈",
value: 693
},{
name: "公有鏈",
value: 611
},{
name: "私有鏈",
value: 512
},{
name: "聯盟鏈",
value: 382
},{
name: "數據共享",
value: 312
},{
name: "文創版權",
value: 187
},{
name: "天河鏈",
value: 163
},{
name: "數據存證",
value: 104
},{
name: "UDFS存儲",
value: 3
},{
name: "在線教育",
value: 31
},{
name: "關聯分析",
value: 941
},{
name: "智慧停車",
value: 585
},{
name: "鏈雲生態",
value: 473
},{
name: "應用層",
value: 358
},{
name: "網絡層",
value: 246
},{
name: "數據層",
value: 207
},{
name: "基礎層",
value: 194
},{
name: "智能合約",
value: 104
},{
name: "去中心化",
value: 87
},{
name: "數字貨幣",
value: 415
},{
name: "酷屏",
value: 253
},{
name: "可視化",
value: 211
},{
name: "P2P",
value: 116
},{
name: "數據挖掘",
value: 1309
}]
}]
}
myChart.setOption(option, true);
window.addEventListener('resize', () => {
myChart.resize();
});
},
},
beforeDestroy() {
clearInterval(this.timer);
}
};
</script>
參考配置說明:https://github.com/ecomfe/echarts-wordcloud
最後
如果感覺還不錯的話,老鐵們是不是來github裏賞個★Star鼓勵一哈。後續會持續更新和優化,也期待大家的交流。
從未停止發表一些實戰型項目的前端技術文章,分享讓更多小夥伴不花錢就能學到前端實戰經驗,也希望能幫助到大家一起成長,能與更多前端大神多交流學習,這是作者的初心。後續主題如下:
- SPA單頁面開發H5移動端和後臺管理系統
- 多頁面應用開發H5移動端和後臺管理系統
- 小程序開發實踐
- 大廠前端性能優化解決方案
- 基於Vuejs大數據可視化大屏
- react native開發APP應用項目
- 區塊鏈相關項目開發