詳解Vue實現(xiàn)直播功能
最近公司剛好在做直播,那么今天就記錄一下遇到的坑,公司服務(wù)器用的亞馬遜aws,所以直接看官方的api就可以了,aws官方地址aws直播api
先看下具體的實現(xiàn)后的效果圖把
按照網(wǎng)上成熟的方法,使用的是video.js,然后aws做了一層封裝,那么我們直接拿來使用把,這里使用vue版本的vue-video-player
先安裝下相關(guān)的包
npm install vue-video-player --save
在main.js引入vue-video-player
// 第一個是videoJs的樣式,后一個是vue-video-player的樣式,因為考慮到我其他業(yè)務(wù)組件可能也會用到視頻播放,所以就放在了main.js內(nèi) require('video.js/dist/video-js.css') require('vue-video-player/src/custom-theme.css') /*導(dǎo)入視頻播放組件*/ import VideoPlayer from 'vue-video-player' Vue.use(VideoPlayer)
導(dǎo)入組件,修改配置參數(shù)
<video-player class="video-player vjs-custom-skin" ref="videoPlayer" :options="playerOptions" @play="onPlayerPlay($event)" @pause="onPlayerPause($event)" @statechanged="playerStateChanged($event)" ></video-player>
修改參數(shù),添加src
playerOptions: { playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度 autoplay: false, //如果true,瀏覽器準(zhǔn)備好時開始回放。 controls: true, //控制條 preload: "auto", //視頻預(yù)加載 muted: true, //默認(rèn)情況下將會消除任何音頻。 loop: false, //導(dǎo)致視頻一結(jié)束就重新開始。 language: "zh-CN", aspectRatio: "16:9", // 將播放器置于流暢模式,并在計算播放器的動態(tài)大小時使用該值。值應(yīng)該代表一個比例 - 用冒號分隔的兩個數(shù)字(例如"16:9"或"4:3") fluid: true, // 當(dāng)true時,Video.js player將擁有流體大小。換句話說,它將按比例縮放以適應(yīng)其容器。 sources: [ { withCredentials: false, type: "application/x-mpegURL", //src: this.liveSrc src: "https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8" } ], poster: this.image, //你的封面地址 //width: 200 || document.documentElement.clientWidth, notSupportedMessage: "此視頻暫無法播放,請稍后再試", //允許覆蓋Video.js無法播放媒體源時顯示的默認(rèn)信息。 controlBar: { timeDivider: true, // 當(dāng)前時間和持續(xù)時間的分隔符 durationDisplay: true, // 顯示持續(xù)時間 remainingTimeDisplay: false, // 是否顯示剩余時間功能 fullscreenToggle: true // 是否顯示全屏按鈕 } },
注意要先測試直播源可以成功播放才可以,否則就會報下這些錯誤
那么我們先按照官方的搭建一個本地的直播源測試吧
先搭建html界面,注意要引入相關(guān)的js庫和文件,我這里用hbuilder,因為用的比較順手,而且預(yù)覽模式類似于開了一個端口,通過get方式的方法,返回了一個本地服務(wù),而不是直接本地雙擊打開html文件,訪問靜態(tài)文件哦~~~~
<!doctype html> <html lang="en"> <head> <link rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.11.4/video.min.js"></script> <script src="https://player.live-video.net/1.4.0/amazon-ivs-videojs-tech.min.js"></script> </head> <body> <div class="video-container"> <video id="amazon-ivs-videojs" class="video-js vjs-4-3 vjs-big-play-centered" controls autoplay playsinline></video> </div> <style> body { margin: 0; } .video-container { width: 640px; height: 480px; margin: 15px; } </style> <script> (function play() { // Get playback URL from Amazon IVS API //var PLAYBACK_URL = 'https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8'; var PLAYBACK_URL = 'https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8' // Register Amazon IVS as playback technology for Video.js registerIVSTech(videojs); // Initialize player var player = videojs('amazon-ivs-videojs', { techOrder: ["AmazonIVS"] }, () => { console.log('Player is ready to use!'); // Play stream player.src(PLAYBACK_URL); }); })(); </script> </body> </html>
通過端口訪問,
后來發(fā)現(xiàn)通過本地靜態(tài)文件,也可以實現(xiàn)在線直播源播放
ps:如果不想自己搭建本機(jī)服務(wù)測試,也可以直接使用awd提供的在線測試
https://replit.com/@changdong0524/amazon-ivs-player-web-sample#samples/common/form-control.ts,但是要自己注冊賬號哦
大概就是下面這樣子哦
大家自己去摸索一下就會了,修改input.value為直播源地址,然后在右邊shell控制臺啟動就可以了
npm install && npm run start
效果如下,是一模一樣的
load這里的地址換成你自己的直播源m3u8格式就好了,我這里是已經(jīng)搭建好的在線直播源
直播源沒問題后,接下來就直接繼續(xù)寫項目代碼
<template> <div class='demo'> <video-player class="video-player vjs-custom-skin" ref="videoPlayer" :playsinline="true" :options="playerOptions" @play="onPlayerPlay($event)" @pause="onPlayerPause($event)" @ended="onPlayerEnded($event)" @waiting="onPlayerWaiting($event)" @playing="onPlayerPlaying($event)" @loadeddata="onPlayerLoadeddata($event)" @timeupdate="onPlayerTimeupdate($event)" @canplay="onPlayerCanplay($event)" @canplaythrough="onPlayerCanplaythrough($event)" @statechanged="playerStateChanged($event)" @ready="playerReadied" > </video-player> </div> </template> <script> export default { methods: { // 播放回調(diào) onPlayerPlay(player) { console.log('player play!', player) }, // 暫停回調(diào) onPlayerPause(player) { console.log('player pause!', player) }, // 視頻播完回調(diào) onPlayerEnded($event) { console.log(player) }, // DOM元素上的readyState更改導(dǎo)致播放停止 onPlayerWaiting($event) { console.log(player) }, // 已開始播放回調(diào) onPlayerPlaying($event) { console.log(player) }, // 當(dāng)播放器在當(dāng)前播放位置下載數(shù)據(jù)時觸發(fā) onPlayerLoadeddata($event) { console.log(player) }, // 當(dāng)前播放位置發(fā)生變化時觸發(fā)。 onPlayerTimeupdate($event) { console.log(player) }, //媒體的readyState為HAVE_FUTURE_DATA或更高 onPlayerCanplay(player) { // console.log('player Canplay!', player) }, //媒體的readyState為HAVE_ENOUGH_DATA或更高。這意味著可以在不緩沖的情況下播放整個媒體文件。 onPlayerCanplaythrough(player) { // console.log('player Canplaythrough!', player) }, //播放狀態(tài)改變回調(diào) playerStateChanged(playerCurrentState) { console.log('player current update state', playerCurrentState) }, //將偵聽器綁定到組件的就緒狀態(tài)。與事件監(jiān)聽器的不同之處在于,如果ready事件已經(jīng)發(fā)生,它將立即觸發(fā)該函數(shù)。。 playerReadied(player) { console.log('example player 1 readied', player); } }, } </script>
定義相關(guān)的監(jiān)聽函數(shù),可以根據(jù)自己需要加上,常用的有下面幾個
onPlayerPlay(player) { console.log("onPlayerPlay", player); }, onPlayerPause(player) { console.log("onPlayerPause", player); }, playerStateChanged(player) { console.log("playerStateChanged", player); },
然后啟動服務(wù)
npm run start
發(fā)現(xiàn)報錯,無法找到相關(guān)的視頻,于是發(fā)現(xiàn)缺少相關(guān)的庫,還得加上aws的庫才可以
在整個項目的index.html中加入下面的庫支持文件
<link rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.11.4/video.min.js"></script> <script src="https://player.live-video.net/1.4.0/amazon-ivs-videojs-tech.min.js"></script>
最后完整效果就出來了
注意事項:
video-player標(biāo)簽的class必須設(shè)置成“video-player vjs-custom-skin”,你引入的樣式才能起作用。 增加hls的支持。支持流媒體m3u8g等等格式播放。
增加hls.js支持,故此要安裝依賴,如下:
npm install --save videojs-contrib-hls
這里提供下aws的官方倉庫啊,需要自取哦
https://github.com/aws-samples
補(bǔ)充一下:如果直接在頁面中實現(xiàn)的話,可能無法直接播放,會報錯無法播放視頻,我猜測可能有2個原因,見截圖
1:異步獲取后臺返回的拉流地址的時候,需要一定的時間,這個時間直播組件已經(jīng)初始化完畢,但是還沒有獲取到直播源地址,所以會報錯找不到直播地址
2:直播組件也有自己一整套完整的生命周期,我們可以檢測不同的生命周期,然后把直播源地址,在請求完畢后放入合適的時間,直播組件會一直請求這個直播地址,從而實現(xiàn)在線直播
這里我為了偷懶,暫時沒有那么多時間去研究一下,等空了會去仔細(xì)研究一下,我是把他抽離出一個單組的子組件,通過props來實現(xiàn)地址的傳遞
效果一樣一樣的,也可以方便其他組件調(diào)用
最后為了方便管理,雙手奉上最后的全部代碼
start
1:main.js
// 第一個是videoJs的樣式,后一個是vue-video-player的樣式,因為考慮到我其他業(yè)務(wù)組件可能也會用到視頻播放,所以就放在了main.js內(nèi) require('video.js/dist/video-js.css') require('vue-video-player/src/custom-theme.css') /*導(dǎo)入視頻播放組件*/ import VideoPlayer from 'vue-video-player' Vue.use(VideoPlayer)
2:videoPlayer.vue
<template> <video-player class="video-player vjs-custom-skin" ref="videoPlayer" :options="playerOptions" @play="onPlayerPlay($event)" @pause="onPlayerPause($event)" @statechanged="playerStateChanged($event)" ></video-player> </template> <script > //import { registerIVSTech } from "amazon-ivs-player"; export default { name: "", props: ["src", "image"], data() { return { // liveSrc: // "https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8", playerOptions: { playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度 autoplay: false, //如果true,瀏覽器準(zhǔn)備好時開始回放。 controls: true, //控制條 preload: "auto", //視頻預(yù)加載 muted: false, //默認(rèn)情況下將會消除任何音頻。 loop: false, //導(dǎo)致視頻一結(jié)束就重新開始。 language: "zh-CN", aspectRatio: "16:9", // 將播放器置于流暢模式,并在計算播放器的動態(tài)大小時使用該值。值應(yīng)該代表一個比例 - 用冒號分隔的兩個數(shù)字(例如"16:9"或"4:3") fluid: true, // 當(dāng)true時,Video.js player將擁有流體大小。換句話說,它將按比例縮放以適應(yīng)其容器。 sources: [ { withCredentials: false, type: "application/x-mpegURL", src: this.src // "https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8" } ], poster: this.image, //你的封面地址 //width: 200 || document.documentElement.clientWidth, notSupportedMessage: "此視頻暫無法播放,請稍后再試", //允許覆蓋Video.js無法播放媒體源時顯示的默認(rèn)信息。 controlBar: { timeDivider: true, // 當(dāng)前時間和持續(xù)時間的分隔符 durationDisplay: true, // 顯示持續(xù)時間 remainingTimeDisplay: false, // 是否顯示剩余時間功能 fullscreenToggle: true // 是否顯示全屏按鈕 } } }; }, // livePlays() { // this.playerOptions.sources[0].src = this.liveSrc; // var obj = {}; // obj.withCredentials = false; // obj.type = "application/x-mpegURL"; // obj.src = this.pullUrl; // this.playerOptions.sources.append(obj); // }, computed: { player() { return this.$refs.videoPlayer.player; } }, computed: { player() { return this.$refs.videoPlayer.player; } }, methods: { onPlayerPlay(player) { console.log("onPlayerPlay", player); }, onPlayerPause(player) { console.log("onPlayerPause", player); }, playerStateChanged(player) { console.log("playerStateChanged", player); } } }; </script>
3:detail.vue 父組件
<template> <d2-container> <div> <div class="webTitle">直播管理 > 大型直播 > 詳情</div> <el-table :data="list" border stripe> <el-table-column align="center" label="直播ID"> <template slot-scope="scope"> <span>{{ scope.row.id }}</span> </template> </el-table-column> <el-table-column align="center" label="直播標(biāo)題"> <template slot-scope="scope"> <span>{{ scope.row.title }}</span> </template> </el-table-column> <el-table-column align="center" label="賬號"> <template slot-scope="scope"> <span>{{ scope.row.name }}</span> </template> </el-table-column> <el-table-column align="center" label="直播開始時間"> <template slot-scope="scope"> <span>{{ scope.row.liveStart | timestampFormat }}</span> </template> </el-table-column> <el-table-column align="center" label="觀看人數(shù)"> <template slot-scope="scope"> <span>{{ scope.row.watchNumber }}</span> </template> </el-table-column> <el-table-column align="center" label="評論數(shù)"> <template slot-scope="scope"> <span>{{ scope.row.reserveNumber }}</span> </template> </el-table-column> <el-table-column align="center" label="購票金額(GP)"> <template slot-scope="scope"> <span>{{scope.row.preSaleType == 1 ? scope.row.preSaleBalance*1 + scope.row.preSaleDeposit *1+ scope.row.fullPayment*1 : scope.row.fullPayment}}</span> </template> </el-table-column> <el-table-column align="center" label="禮物金額"> <template slot-scope="scope"> <span>{{ scope.row.reserveNumber }}</span> </template> </el-table-column> </el-table> <div class="playWrap"> <div class="livePicture"> <vueVideoPlayers :src="src" :image="image" /> </div> <div class="liveCommet"></div> </div> <div class="playWrap"> <div class="playLeft"> <p>基本信息</p> <ul class="leftInfo"> <li class="playItem"> <span class="playTitle">分類</span> <span class="playContent">{{typeName}}</span> </li> <li class="playItem"> <span class="playTitle">預(yù)售類型</span> <span class="playContent">{{formData.preSaleType == 1 ? "預(yù)售" :"非預(yù)售"}}</span> </li> <li class="playItem"> <span class="playTitle">是否錄播</span> <span class="playContent">{{formData.isRecordedBroadcast ==1 ? "錄播" : "不錄播"}}</span> </li> <li class="playItem"> <span class="playTitle">演員列表</span> <span class="playContent">{{formData.actor}}</span> </li> <li class="playItem"> <span class="playTitle">直播介紹</span> <span class="playContent">{{formData.liveIntroduce}}</span> </li> </ul> <p>預(yù)售信息</p> <ul class="leftInfo"> <li class="playItem"> <span class="playTitle">預(yù)售時段</span> <span class="playContent"> {{formData.preSaleStart}} <span style="color:#333;margin:0 5px">-</span> {{formData.preSaleEnd}} </span> </li> <li class="playItem"> <span class="playTitle">成型人數(shù)</span> <span class="playContent">{{formData.formingNum ? formData.formingNum : 0}}</span> </li> <li class="playItem"> <span class="playTitle">成型狀態(tài)</span> <span class="playContent" >{{formData.reserveNumber > formData.reserveNumber ? "已成型":"未成型" }}</span> </li> </ul> <p>非預(yù)售信息</p> <ul class="leftInfo"> <li class="playItem"> <span class="playTitle">售票開始時間</span> <span class="playContent">{{formData.ticketingStart}}</span> </li> </ul> <p>票價</p> <ul class="leftInfo"> <li class="playItem"> <span class="playTitle">預(yù)售定金</span> <span class="playContent">{{formData.preSaleDeposit ? formData.preSaleDeposit : 0}}</span> </li> <li class="playItem"> <span class="playTitle">預(yù)售尾款</span> <span class="playContent">{{formData.preSaleBalance ? formData.preSaleBalance : 0}}</span> </li> <li class="playItem"> <span class="playTitle">全款價格</span> <span class="playContent">{{formData.fullPayment ? formData.fullPayment : 0}}</span> </li> <li class="playItem"> <span class="playTitle">回放價格</span> <span class="playContent">{{formData.playbackPrice ? formData.playbackPrice : 0}}</span> </li> </ul> </div> <div class="playRight"> <p>圖像資料</p> <ul class="leftInfo"> <li class="playItem"> <span class="playTitle">宣傳視頻</span> <span class="playContent"> <img v-if="formData.propagandaVideoUrl" :src="videoPng" class="playImage" @click="showVideo(formData.propagandaVideoUrl,true)" /> <span v-else style="color:#cfcfcf">暫無視頻</span> </span> </li> <li class="playItem"> <span class="playTitle">回訪視頻</span> <span class="playContent"> <img v-if="formData.recordedBroadcastUrl" :src="videoPng" class="playImage" @click="showVideo(formData.recordedBroadcastUrl,false)" /> <span v-else style="color:#cfcfcf">暫無視頻</span> </span> </li> <li class="playItem"> <span class="playTitle">分享海報</span> <span class="playContent"> <el-image class="matchImg" :src="formData.shareImage" :preview-src-list="[formData.shareImage]" /> </span> </li> <li class="playItem"> <span class="playTitle">封面圖片</span> <span class="playContent"> <el-image class="matchImg" v-for="(item,index) in JSON.parse(formData.coverImage)" :src="item" :key="index" :preview-src-list="[item]" /> </span> </li> </ul> <!-- <p>圖像資料</p> <ul class="leftInfo"></ul>--> </div> </div> </div> <el-button @click="backPage">返回</el-button> <el-dialog title="查看" :visible.sync="videoVisible" width="850px"> <div v-if="video"> <video :src="tempSrc" controls="controls" width="800" height="600">您的瀏覽器不支持 video 標(biāo)簽。</video> </div> <div v-else> <vueVideoPlayers :src="tempSrc" :image="image" /> </div> </el-dialog> </d2-container> </template> <script > import { getLiveDetail, getLiveSellDetail } from "@/api/3d/liveApi"; import videoPng from "@/assets/img/video.jpg"; import { timestampFormat } from "@/common/filters"; //import { registerIVSTech } from "amazon-ivs-player"; import vueVideoPlayers from "./videoPlayer"; export default { name: "", data() { return { src: "", //直播源視頻 image: "", videoPng: videoPng, video: true, videoVisible: false, // videoSrc: "", //宣傳視頻 // recordedBroadcastUrl:'', //回放視頻 tempSrc: "", list: [], id: "", typeName: "", pullUrl: "", formData: { id: "", pullUrl: "", pushUrl: "", title: "", liveIntroduce: "", actor: "", typeId: "", isRecordedBroadcast: 2, coverImage: "", propagandaVideoUrl: "", formingNum: "", preSaleDeposit: "", //預(yù)售定金價格 preSaleBalance: "", //預(yù)售尾款價格 fullPayment: "", //全款價格 playbackPrice: "", //回放價格 preSale: [], //預(yù)售時間 preSaleStart: "", preSaleEnd: "", liveStart: "", //直播開始時間 isSpeak: 1, priority: "", shareImage: "" } }; }, created() { this.getLiveSell(); this.getData(); }, mounted() {}, components: { vueVideoPlayers }, methods: { backPage() { this.$router.push("/liveMange/largeBrand"); }, //售票情況 getLiveSell() { var id = this.$route.params.id; getLiveSellDetail(id).then(res => { const result = res.data; }); }, //彈框打開看視頻 showVideo(playSrc, mark) { this.videoVisible = true; this.video = mark; this.tempSrc = playSrc; }, getData() { var id = this.$route.params.id; this.id = id; //var localMatchTypeId=localStorage.getItem('matchTypeId') //var localPriority = localStorage.getItem('priority') // var data = { id, page: 1, limit: 10 }; getLiveDetail(id).then(res => { const result = res.data; //沒有分類ID取本地 // if(!result.matchTypeId){ // result.matchTypeId = localMatchTypeId // } // if(!result.priority){ // result.priority = localPriority // } this.formData = result; let { pullUrl, pushUrl, coverImage } = result; this.src = pullUrl; this.image = JSON.parse(coverImage)[0]; const { id, title, liveStart, ticketingStart, playbackPrice, preSaleDeposit, preSaleBalance, fullPayment } = result; const objData = { id, title, name: "admin", liveStart, watchNumber: localStorage.getItem("watchNumber") | 0, reserveNumber: localStorage.getItem("reserveNumber") | 0, preSaleDeposit, preSaleBalance, fullPayment, ticketingStart, playbackPrice }; this.list.push(objData); // this.formData.registrationStart=result.registrationStart + '' // this.formData.registrationEnd = result.registrationEnd + '' // this.formData.voteStart = result.voteStart + '' // this.formData.voteEnd = result.voteEnd + '' //投票時段 // var preSaleStart = moment(parseInt(result.preSaleStart)).format( // "YYYY-MM-DD hh:mm:ss:SSS" // ); // var preSaleEnd = moment(parseInt(result.preSaleEnd)).format( // "YYYY-MM-DD hh:mm:ss:SSS" // ); //賽事結(jié)束時段 // this.formData.liveStart = new Date(result.liveStart); //this.formData.registration.push(start) //this.formData.registration.push(end) //手動賦值 // this.$set(this.formData, "preSale", [preSaleStart, preSaleEnd]); //this.$set(this.formData, "vote", [voteStart, voteEnd]); //日期格式化 //預(yù)售 時間段 this.formData.preSaleStart = result.preSaleStart ? timestampFormat(result.preSaleStart) : ""; this.formData.preSaleEnd = result.preSaleEnd ? timestampFormat(result.preSaleEnd) : ""; //非預(yù)售 開始售票時間 this.formData.ticketingStart = result.ticketingStart ? timestampFormat(result.ticketingStart) : ""; this.typeName = localStorage.getItem("typeName") || ""; }); } } }; </script> <style scoped> .playWrap { display: flex; background: #fff; margin-top: 20px; } .leftInfo { list-style: none; border: 1px solid #cfcfcf; } .playLeft { width: 48%; /* border: 1px solid #f5f5f5; */ } .playRight { width: 48%; margin-left: 2%; } .playItem { display: flex; align-items: center; padding: 10px 0; border-bottom: 1px solid #cfcfcf; } .playItem:last-child { border-bottom: none; } .playContent { margin-left: 20px; color: #999; } .matchImg { width: 80px; height: 80px; margin-right: 10px; } .playImage { width: 80px; height: 80px; } .playWrap { display: flex; } .livePicture { width: 40%; height: 400px; } </style>
3:index.html記得加入如下代碼
<link rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.11.4/video.min.js"></script> <script src="https://player.live-video.net/1.4.0/amazon-ivs-videojs-tech.min.js"></script>
end
加油~~~~
到此這篇關(guān)于Vue實現(xiàn)直播功能的文章就介紹到這了,更多相關(guān)Vue實現(xiàn)直播內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue綁定class和綁定內(nèi)聯(lián)樣式的實現(xiàn)方法
本文主要介紹了Vue綁定class和綁定內(nèi)聯(lián)樣式的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11關(guān)于ElementPlus中的表單驗證規(guī)則詳解
這篇文章主要介紹了關(guān)于ElementPlus中的表單驗證,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06vue?select組件綁定的值為數(shù)字類型遇到的問題
這篇文章主要介紹了vue?select組件綁定的值為數(shù)字類型遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09Vue 使用formData方式向后臺發(fā)送數(shù)據(jù)的實現(xiàn)
這篇文章主要介紹了Vue 使用formData方式向后臺發(fā)送數(shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04解決VUE mounted 鉤子函數(shù)執(zhí)行時 img 未加載導(dǎo)致頁面布局的問題
這篇文章主要介紹了解決VUE mounted 鉤子函數(shù)執(zhí)行時 img 未加載導(dǎo)致頁面布局的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07