開發(fā)一個封裝iframe的vue組件
VUE的基本組成單元,我看應(yīng)該是組件。用VUE開發(fā)前端項目,就是開發(fā)一個個組件,然后搭積木一樣,將項目搭建出來。組件包含在頁面,或者是更大的組件里面。在這里,組件與頁面的界限,好像并不明顯。事實上,對于單頁應(yīng)用,只有一個頁面。
組件的好處,一是可以加強復(fù)用;二是能夠?qū)⑻囟üδ芊庋b,利于調(diào)用;三是由于職責(zé)分明,組件高內(nèi)聚,組件間低耦合,利于系統(tǒng)功能的優(yōu)化、擴展和維護。好處多多。
開發(fā)組件,主要有2部分內(nèi)容:
1、組件內(nèi)部邏輯
2、外部接口
由于我這兩天弄的組件,里面包含有一個<iframe>,那么還有一部分工作內(nèi)容:
3、iframe接口
一、組件介紹
這是一個地圖插件。功能是展示地圖,以及接受外部命令,加載圖層、繪制圖形等相關(guān)操作。地圖采用arcgis for js實現(xiàn)。由于我們過去開發(fā)的項目,地圖操作有一些積累,不過并沒有前后端分離,沒有采用VUE或REACT,還是傳統(tǒng)的WEB頁面。因為時間緊,也想直接復(fù)用以前的成果,于是考慮用<iframe>承載地圖頁面,封裝在VUE組件里,由組件對接外部命令并與iframe里的地圖頁面交互。
二、組件內(nèi)部結(jié)構(gòu)及邏輯
1、代碼組織結(jié)構(gòu)

2、地圖組件
Map.vue
<template>
<div class="map-container">
<!-- 承載地圖頁面 -->
<iframe :src="src" ref="iframe" @load="iframeLoad"></iframe>
</div>
</template>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped="scoped">
.map-container iframe{
width: 100%;
height: 100%;
border: none;
}
</style>
<script>
import config from '../../vue.config'//里面有路徑信息
let iframeWin = null;//私有變量
export default {
props:['size'],//純測試,沒啥用,對應(yīng)<Map id="map" ref="map" size="100"></Map>
data() {
return {
src: '',//地圖頁面地址
isLoaded: false,//地圖頁面是否加載完畢
iMap: null,//地圖頁面暴露出來的,供外部訪問的對象
require: null//arcgis的require函數(shù),用于引用自定義插件。我們過去寫了不少自定義的地圖插件
}
},
created() {
this.src = config.publicPath + 'map.html'
},
mounted() {
//監(jiān)聽iframe的消息
window.addEventListener('message', this.handleMessage)
iframeWin = this.$refs.iframe.contentWindow
},
methods: {
iframeLoad() {
this.isLoaded = true;
window.console.log("map is ready")
},
async handleMessage() {//接收來自iframe的消息
this.require = iframeWin.require;
this.iMap = iframeWin.iMap;
},
loadLayer(nodes,servers){
this.iMap.layerHandler.load(nodes,servers);
},
isReady(){
return this.isLoaded;
}
}
}
</script>
有關(guān)組件的結(jié)構(gòu),比如
export default {
props:,//標記里的屬性
data() {//公共變量
},
created() {//加載時?
},
mounted() {//加載完畢時
},
methods: {//公共方法
}
}
export代表了這是對外。所以里面的屬性、變量、方法,都可以被外部訪問。如果想私有,應(yīng)該在export之外定義。如本例:

像這類簡單的介紹,在網(wǎng)上怎么也搜不到。vue的中文站點,陳舊,內(nèi)容支離破碎,對初學(xué)者極不友好,加重了學(xué)習(xí)的成本。
三、iframe接口
組件Map.vue與里面的iframe是怎么通信的呢?
通過系統(tǒng)消息和直接訪問iframe的對象。直接訪問iframe里的對象有個前提,就是不能跨域。
iframe承載的地圖頁面map.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
...
</head>
<body>
<div id="map"></div>
...
</div>
</body>
</html>
<script src="http://192.168.0.200/pubzy211/arcgis_js_api/3.19/init.js"></script>
<script type="text/javascript">
var iMap = {}; //外部引用接口
require([
"esri/config",
"esri/map",
"esri/geometry/Extent",
"esri/SpatialReference",
"layerlib/LtLayer",
"dojo/dom",
"dojo/_base/array",
"dojo/parser",
"dojo/domReady!"
], function(
esriConfig,
Map,
Extent,
SpatialReference,
LtLayer,
dom,
arrayUtils,
parser
) {
//map
var map = ...
/* 外部接口 */
iMap = {
map: map,
legend: legend,
home: home,
tipDialog: tipDialog,
toggle: toggle,
overviewMap: overviewMap
};
iMap.drawHandler = ...
iMap.layerHandler = ...;
iMap.centerAt = ...;
iMap.clear = ...;
iMap.restoreView = ...;
// 向父vue頁面發(fā)送加載完畢信號
window.parent.postMessage({
cmd: 'mapIsReady',
params: {
success: true,
data: true
}
}, '*');
/* end of 外部接口 */
});
</script>
地圖組件Map.vue對應(yīng)iframe部分,詳見一.2中的代碼
export default {
。。。
mounted() {
//監(jiān)聽iframe的消息
window.addEventListener('message', this.handleMessage)
//獲得iframe的window對象
iframeWin = this.$refs.iframe.contentWindow
},
methods: {
iframeLoad() {
this.isLoaded = true;
window.console.log("map is ready")
},
async handleMessage() {//接收來自iframe的消息
this.require = iframeWin.require;
this.iMap = iframeWin.iMap;
},
loadLayer(nodes,servers){
//加載圖層
this.iMap.layerHandler.load(nodes,servers);
}
}
}
四、外部接口
Map.vue是一個組件,它要跟它所在的組件或頁面進行通信。
現(xiàn)在,Map.vue放在了一個容器頁面Home.vue(即測試頁面)里,里面還有一個命令組件Layer.vue。點擊命令組件里的按鈕,地圖要做出相應(yīng)的響應(yīng)。其中的原理如下:
命令組件的按鈕點擊后,發(fā)射信息到容器頁面,然后容器頁面調(diào)用地圖組件的方法。
測試頁面Home.vue
<template>
<div id="app1">
<div id="map-container">
<div>地圖組件</div>
<Map id="map" ref="map" size="100"></Map>
</div>
<div id="layer-container">
<div>其他組件</div>
<Layer @loadLayer="loadLayer" @loadCloud="loadCloud" @clear="clearMap"></Layer>
</div>
</div>
</template>
<script>
import Map from '../components/Map.vue'
import Layer from '../components/Layer.vue'
export default {
name: 'App',
components: {
Map,
Layer
},
methods:{
loadLayer(nodes,servers){//加載圖層
let map = this.$refs.map;
map.loadLayer(nodes,servers);
},
loadCloud(data){//加載衛(wèi)星云圖
let map = this.$refs.map;
map.require(["drawlib/Cloud"], function (Cloud) {
let iMap = map.iMap;
let cloudId = 'cloud';
let cloud = new Cloud(iMap.map);
iMap.drawHandler.push(cloudId, cloud);
cloud.draw(data,cloudId);
});
},
clearMap(){//清除
let map = this.$refs.map;
map.iMap.clear();
}
}
}
</script>
<style>
。。。
</style>
命令組件Layer.vue
<template>
<div class="layer-container">
<button @click="loadLayer">加載圖層</button>
<button @click="loadCloud">衛(wèi)星云圖</button>
<button @click="clear">清除</button>
</div>
</template>
<script>
export default {
methods: {
loadLayer() {
let nodes = ...
let servers = ...
this.$emit("loadLayer", nodes,servers)
},
loadCloud(){
let data = ...;
this.$emit("loadCloud", data);
},
clear(){
this.$emit("clear");
}
},
}
</script>
<style scoped="scoped">
。。。
</style>
注意命令組件發(fā)射消息中指定的方法,在容器頁面中都有相關(guān)的屬性與之對應(yīng):
命令組件
loadCloud(){
let data = ...;
this.$emit("loadCloud", data);
},
容器頁面
<Layer @loadLayer="loadLayer" @loadCloud="loadCloud" @clear="clearMap"></Layer>
五、運行結(jié)果

六、總結(jié)
其他組件要與地圖組件交互,中間要通過容器頁面,其他組件與地圖組件并沒有直接交互。這其實是一種命令模式。好處是其他組件和地圖組件解耦,沒有耦合在一起,意味著互不影響。這有利于地圖組件本身的擴展和優(yōu)化。缺點的話,每個東東都要通過容器頁面轉(zhuǎn)發(fā),容器頁面代碼可能會有冗余,有些方法根本就是個傳聲筒,給人的感覺是重重復(fù)復(fù)的寫,意義不太大。
以上就是開發(fā)一個封裝iframe的vue組件的詳細內(nèi)容,更多關(guān)于封裝iframe的vue組件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue3中Element Plus Table(表格)點擊獲取對應(yīng)id方式
這篇文章主要介紹了Vue3中Element Plus Table(表格)點擊獲取對應(yīng)id方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
Vue中this.$router.push參數(shù)獲取方法
下面小編就為大家分享一篇Vue中this.$router.push參數(shù)獲取方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02
vue基于mint-ui的城市選擇3級聯(lián)動的示例
本篇文章主要介紹了vue基于mint-ui的城市選擇3級聯(lián)動的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10

