您好,登錄后才能下訂單哦!
這篇文章主要講解了“Vue中怎么根據主題獲取不同的資源切換圖片”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Vue中怎么根據主題獲取不同的資源切換圖片”吧!
最近公司的一個小游戲Y需要實現本土化主題,即不同地區需要展示不同的主題,而且游戲的圖片眾多,如何優雅快速得加載正確的皮膚圖片就變得尤為重要。
css樣式切換社區里已經有很多方案,可以自行參考,該文章已經講得非常詳細,這里不再贅述,本文主要講講如何根據主題獲取不同的資源切換圖片。
圖片換膚,根據以往經驗,得益于webpack的依賴管理,我們一般是使用require引入圖片。比如這種寫法(require(`@assets/img/${theme}/bg.png`))
,webpack會將@assets/img
中的所有文件都加入到bundle中,從而在運行的時候可以找到對應的圖片。具體實現如下:
<template> <!-- 這里需要判斷圖片是否存在,如果不存在需要指定為auto,不然會引起404,導致系統告警 --> <div class="y-content" :style="{backgroundImage: contentBg ? `url(${contentBg})` : 'auto'}"> <img class="y-content__reward" :src="rewardImg" /> </div> </template> <script> data: () => ({ theme: 'blcak' }), computed: { contentBg() { try { // this.theme是文件夾,將不同的皮膚放到不同的文件夾,用同樣的命名 return require(`@assets/img/${this.theme}/contentBg.png`) } catch (err) { return ''; } }, rewardImg() { try { return require(`@assets/img/${this.theme}/rewardImg.png`) } catch (err) { return ''; } } } </script>
以上代碼基本上能解決大部分的換膚需求,但是對于圖片需要預先加載的項目,我們還需要區分不同主題的圖片便于優化提前加載,由于編譯后的圖片鏈接跟編譯前的鏈接是不同,因此我們獲取編譯后的圖片鏈接。一般的項目中比如使用官方腳手架vue-cli
構建的項目,所有的圖片都會被url-loader
處理后放到同一個文件夾image當中,這樣編譯前不同文件夾相同名字的圖片編譯后之后hash
是不同,因此我們是無法區分不同主題的圖片的。
于是,首先我們需要將不同的主題圖片放置到不同的文件夾當中,同樣適用用url-loader
// vue-cli配置 const imagesRule = config.module.rule('images'); imagesRule.uses.clear() //清除原本的images loader配置 imagesRule .test(/white/.+.(jpg|gif|png|svg)$/) .use('url-loader') .loader('url-loader') .options({ name:"img/white/[name].[hash:8].[ext]", limit: 8192 }) // 加多一個主題的配置 config.module .rule('image2') .test(/black/.+.(jpg|gif|png|svg)$/) .use('url-loader') .loader('url-loader') .options({name:"img/black/[name].[hash:8].[ext]", limit: 8192 }) // 自定義webpack配置 rules: [ { test: /white/.+.(png|svg|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192, name: 'img/white/[name].[hash:8].[ext]', } } ], }, { test: /black/.+.(png|svg|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192, name: 'img/black/[name].[hash:8].[ext]', } } ], }, ]
這樣子編譯后不同主題的圖片就會被放置到不同的文件夾當中,這樣就結束了嗎?還沒有,我們還需要獲取編譯后的圖片鏈接,才能在進入游戲頁面的時候提前加載主題圖片,這里我們可以寫一個webpack plugin來幫我們收集相應的圖片,生產各自主題的json文件。插件代碼如下:
// webpack版本為4.x class WebPackSouceManifest { // 將 `apply` 定義為其原型方法,此方法以 compiler 作為參數 constructor(option = {}) { // 黑色主題的文件名 this.blackManifestName = option.blackManifestName || 'js/blackManifest.json' // 白色主題的文件名 this.whiteManifestName = option.whiteManifestName || 'js/whiteManifest.json' this.blackJsonData = { code: 0, data: [] } this.whiteJsonData = { code: 0, data: [] } this.addFileToSouceManifest.bind(this) } apply(compiler) { // 指定要附加到的事件鉤子函數 compiler.hooks.emit.tapAsync( 'HashServiceWorkerStartPlugin', (compilation, callback) => { const allBuildFiles = Object.keys(compilation.assets) allBuildFiles.forEach((file) => { if (file.indexOf('white') !== -1) { this.addFileToSouceManifest('white', file) } else { this.addFileToSouceManifest('black', file) } }) const sourceBlack = JSON.stringify(this.blackJsonData) const sourceWhite = JSON.stringify(this.whiteJsonData) compilation.assets[this.blackManifestName] = { source: () => { return sourceBlack; }, size: () => { return sourceBlack.length; } } compilation.assets[this.whiteManifestName] = { source: () => { return sourceWhite; }, size: () => { return sourceWhite.length; } } callback() } ); } addFileToSouceManifest(type, file) { let fileItem = { src: file, } if (/.js$/.test(file)) { fileItem.type = 'text' } else if (/.js.map$/.test(file)) { fileItem.type = 'json' } if (type === 'white') { this.whiteJsonData.data.push(fileItem) } else { this.blackJsonData.data.push(fileItem) } } } module.exports = WebPackSouceManifest;
因此我們得到不同主題的圖片列表json,在進入頁面的時候通過ajax獲取到列表之后對別表中的圖片進行加載,雖然以上的做法可以實現需求,但是實在太過復雜?那還有沒有輕松的方式呢?當然是有的。
仔細分析上面的代碼后她,我們最終要獲得的是圖片編譯后的結果,所以如果我們能夠生成一個圖片對象,將圖片的name
當作key,圖片編譯后的結果當作value,那么上面的代碼將可以簡化為如下:
<template> <!-- 這里需要判斷圖片是否存在,如果不存在需要指定為auto,不然會引起404,導致系統告警 --> <div class="y-content" :style="{backgroundImage: contentBg ? `url(${contentBg})` : 'auto'}"> <img class="y-content__reward" :src="rewardImg" /> </div> </template> <script> data: () => ({ theme: 'middleEast' }), computed: { contentBg() { // skinImage是跟組件下的字段 return this.$root.skinImage['contentBg'] // contentBg為name }, rewardImg() { return this.$root.skinImage['rewardImg'] } } </script>
如此代碼變得簡潔,不需要通篇的require跟try catch,接下來我們來如何實現這個skinImage對象呢
答案就是使用webpack的require.context
通過執行require.context函數獲取一個特定的上下文,主要用來實現自動化導入模塊,在前端工程中,如果遇到從一個文件夾引入很多模塊的情況,可以使用這個api,它會遍歷文件夾中的指定文件,然后自動導入,使得不需要每次顯式的調用import導入模塊,具體用法這里不再贅述,
詳細請查看官方文檔 requirecontext
https://webpack.docschina.org/guides/dependency-management/#requirecontext
于是我們來寫一個自動導入圖片并生成skinImage對象的函數
const black = require.context('../black', true, /.(png|jpg|gif)$/); const middleImageObj = {}; black.keys().forEach(path => { // 獲取圖片的key const key = path.slice(2, -4); blackImageObj[key] = rawSkin(path); });
這樣子我們就得到了黑色主題的圖片對象,由于require.context的執行是在編譯過程而不是運行時,所以所有的參數只能是靜態的,這里我們還需要將白色主題的圖片也提前獲取,如下
const black = require.context('../black', true, /.(png|jpg|gif)$/); const middleImageObj = {}; black.keys().forEach(path => { // 獲取圖片的key const key = path.slice(2, -4); blackImageObj[key] = rawSkin(path); });
這樣我們就得到了兩個主題的圖片對象,接下來只要將某一個對象賦值給根組件的skinImage,就大功告成了,是不是比起上面的要更簡單,更簡潔。
感謝各位的閱讀,以上就是“Vue中怎么根據主題獲取不同的資源切換圖片”的內容了,經過本文的學習后,相信大家對Vue中怎么根據主題獲取不同的資源切換圖片這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。