因爲該項目是基於本來的安卓app,作的微信h5,因此原來的使用webview的頁面如今須要在vue中實現,那就是使用iframe
查看了不少不少文檔,其中這一篇是頗有價值的 https://gist.github.com/pboji... css
下面將3天的爬坑最終以問答的方式總結以下:html
一、Vue組件中如何引入iframe?vue
二、vue如何獲取iframe對象以及iframe內的window對象?jquery
三、vue如何向iframe內傳送信息?git
四、iframe內如何向外部vue發送信息?github
一、Vue組件中如何引入iframe?web
<template> <div class="act-form"> <iframe :src="src"></iframe> </div> </template> <script> export default { data () { return { src: '你的src' } } } </script>
如上,直接經過添加iframe標籤,src屬性綁定data中的src,第一步引入就完成了
二、vue如何獲取iframe對象以及iframe內的window對象?api
在vue中,dom操做比不上jquery的$('#id')來的方便,可是也有辦法,就是經過ref
<template> <div class="act-form"> <iframe :src="src" ref="iframe"></iframe> </div> </template> <script> export default { data () { return { src: '你的src' } }, mounted () { // 這裏就拿到了iframe的對象 console.log(this.$refs.iframe) } } </script>
而後就是獲取iframe的window對象,由於只有拿到這個對象才能向iframe中傳東西緩存
<template> <div class="act-form"> <iframe :src="src" ref="iframe"></iframe> </div> </template> <script> export default { data () { return { src: '你的src' } }, mounted () { // 這裏就拿到了iframe的對象 console.log(this.$refs.iframe) // 這裏就拿到了iframe的window對象 console.log(this.$refs.iframe.contentWindow) } } </script>
三、vue如何向iframe內傳送信息?sass
經過postMessage,具體關於postMessage是什麼,本身去google, 個人理解postMessage是有點相似於UDP協議,就像短信,是異步的,你發信息過去,可是沒有返回值的,只能內部處理完成之後再經過postMessage向外部發送一個消息,外部監聽message 爲了讓postMessage像TCP,爲了體驗像同步的和實現多通訊互不干擾,特別制定的message結構以下
{ cmd: '命令', params: { '鍵1': '值1', '鍵2': '值2' } }
經過cmd來區別這條message的目的
具體代碼以下
<template> <div class="act-form"> <iframe :src="src" ref="iframe"></iframe> <div @click="sendMessage">向iframe發送信息</div> </div> </template> <script> export default { data () { return { src: '你的src', iframeWin: {} } }, methods: { sendMessage () { // 外部vue向iframe內部傳數據 this.iframeWin.postMessage({ cmd: 'getFormJson', params: {} }, '*') }, }, mounted () { // 在外部vue的window上添加postMessage的監聽,而且綁定處理函數handleMessage window.addEventListener('message', this.handleMessage) this.iframeWin = this.$refs.iframe.contentWindow }, handleMessage (event) { // 根據上面制定的結構來解析iframe內部發回來的數據 const data = event.data switch (data.cmd) { case 'returnFormJson': // 業務邏輯 break case 'returnHeight': // 業務邏輯 break } } } </script>
四、iframe內如何向外部vue發送信息?
如今經過點擊「向iframe發送信息」這個按鈕,從外部vue中已經向iframe中發送了一條信息
{ cmd: 'getFormJson', params: {} }
那麼iframe內部如何處理這個信息呢?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>iframe Window</title> <style> body { background-color: #D53C2F; color: white; } </style> </head> <body> <h1>Hello there, i'm an iframe</h1> <script> // 向父vue頁面發送信息 window.parent.postMessage({ cmd: 'returnHeight', params: { success: true, data: document.body.scrollHeight + 'px' } }, '*'); // 接受父頁面發來的信息 window.addEventListener("message", function(event){ var data = event.data; switch (data.cmd) { case 'getFormJson': // 處理業務邏輯 break; } }); </script> </body> </html>
至此內部的收發信息已經解決了,外部的收發也已經解決了,快去解決你的問題吧
在這裏先直接給出我項目的源碼
<template> <div class="act-form"> <div class="nav"> <img src="https://cxkccdn.oss-cn-shanghai.aliyuncs.com/lesai_img/icon_back_white.png" @click="back()"> <div class="title">報名</div> </div> <div class="iframe-out"> <iframe :src="src" ref="iframe" @load="iframeLoad"></iframe> </div> <div v-if="isLoaded" class="send-form"><div class="send" @click="sendMessage()">提交</div></div> </div> </template> <!-- Add "scoped" attribute to limit CSS to this component only --> <style lang="sass" rel="stylesheet/sass"> @import "style.scss"; </style> <script> import { Toast, Indicator } from 'mint-ui' import api from '@/utils/api' export default { data () { return { src: '', iframeWin: null, isLoaded: false } }, created () { let matchFamily = this.$store.state.matchFamily this.src = process.env.BASE_URL + '/matches/' + matchFamily.match.id + '/act/' + matchFamily.act.id + '/joinweb?token=' + this.$store.state.token }, mounted () { window.addEventListener('message', this.handleMessage) this.iframeWin = this.$refs.iframe.contentWindow // 開啓加載動畫 Indicator.open({ text: '努力加載中...', spinnerType: 'triple-bounce' }) }, methods: { back () { this.$router.push('/actIntro') }, sendMessage () { this.iframeWin.postMessage({ cmd: 'getFormJson', params: {} }, '*') }, iframeLoad () { // 關閉加載動畫 Indicator.close() }, async handleMessage (event) { const data = event.data switch (data.cmd) { case 'returnFormJson': if (data.params.success) { // 調用報名方法 await this.enroll(data.params.data) } else { console.log('returnFormJson失敗') console.log(data.params) } break case 'returnHeight': if (data.params.success) { this.$refs.iframe.height = data.params.data this.isLoaded = true } break } }, async enroll (data) { let matchFamily = this.$store.state.matchFamily let result = await api.enroll(matchFamily.match.id, matchFamily.act.id, data) if (result.success) { if (result.data.status === 'no_pay') { // 更新緩存 let resultMatch = await api.match(matchFamily.match.id, {}) if (resultMatch.success) { this.$store.commit('SET_CURRENT_MATCH', resultMatch.data) } Toast({ message: '報名成功', position: 'bottom' }) this.$router.push('/match/' + matchFamily.match.id + '/mdetail') } else { console.log('須要跳轉到支付頁面') } } } } } </script>
歡迎你們來看看個人博客 https://www.windzh.com