一次與客戶端合作的走坑之旅!


    項目經理給客戶端提出了個需求,加急做用戶反饋界面,很急,安卓客戶端項目開發就一個人,表示干不了,短時間內完成不了,於是商量了一番,把前端的我攪和進去了,讓新增的用戶反饋界面用H5開發。甩鍋於前端,經理說趕緊做,當天要!於是那天臨近午飯時間,通知這個事情讓我干,我心里是真的不是滋味,心里mmp。隨即給我UI,告訴我說UI會裁好圖給我。這圖一直到下午4點,離下班還有兩個小時的時候才給我的。這種做事效率讓人心塞啊!但是也顧不得抱怨了,三下五除二,使用vue+vue-router+vant足以滿足需求開發了。最終在下班之前還是打包交給服務器端了。

  服務器端部署項目之后,打開界面,白屏界面不出來,而且還不報錯!這就尷尬了,沒報錯那是真的難找問題。他們服務器的人也倒騰了半天,沒效果,我就不信邪,我說我以前打包的項目都是這樣的,沒出現過這樣的問題。我就把這個項目部署在了自己的阿里雲服務器上,試試看,卻能看到界面效果!這就摸不着頭腦了,問題還是要解決的。試了幾次,終於找到了問題,router的history模式導致的問題。因為我自己的服務器的nginx配置時對這個mode進行了處理的,所有是沒有問題,而這個項目的服務器端時沒有對這個模式進行匹配處理的。那就先來說說vue-router的history模式了。

  HTML5 History模式

  vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新加載。如果不想要很丑的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。

const Router = require('vue-router')
const router = new Router({
   mode:'history',
   routes: [...]  
})

當使用history模式時,url就像正常的url如https://i.cnblogs.com/EditPosts.aspx?opt=1。不過這種模式要玩好,還需要后台配置支持。因為我們的應用是個單頁客戶端應用,如果后台沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就不好看了。所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

后台服務器nginx的配置需加上:

location / {
  try_files $uri $uri/ /index.html;
}

完整的vue-router 的history模式可以點此學習:https://router.vuejs.org/zh/guide/essentials/history-mode.html

由於當時服務器沒有對這個history模式進行nginx配置,我只好把router處的mode:'history'去掉。后面那些路由不好看的啥子東西服務器那邊配置的時候自行解決了。

  本以為都告一段落了,誰知這才剛剛開始。測試站測試人員提bug了。客戶端測試人員用的安卓機,可不是正常的手機,是用那種低端機進行測試的,所以與我們在稍好一點的手機上看到的效果差別還是很明顯的。測試人員說:進入H5頁面會有閃屏出現,那個banner圖片會閃一下再出來,體驗很不好。

我看了一下效果之后,我那是就有點底了,h5剛出來的時候,本應該是banner占據的位置,被下面的內容占據了,我心中一想可能是沒有給圖片的容器進行高度設置,才讓這種閃屏出現。我覺得還應該對圖片進行壓縮處理,因為在移動端,對圖片的壓縮還是非常有必要的。雖然有時候有些損失圖片的質量,但是其實在移動端,還是很難覺察到差別的。經過了對圖片的高度設置和壓縮之后,這種閃屏好了很多。

  解決了這個閃屏bug,滿以為可以了。可是客戶端的需求是不斷改變的。客端戶需要在無網絡狀態下,進入h5首頁,然后連網之后,可以在頁面上進行交互。

  我當時腦子是蒙的,我是拒絕的,我說這個應該是你們客戶端解決的事情吧,客戶端人員說需要三份代碼,因為我們坐的這個用戶反饋h5是有三種不同的語言的,中文、印尼語和英文,所以還是需要打包三份代碼,用以針對三種不同語言的需求。以保存在客戶端本地。打包好三份代碼給客戶端之后,客戶端在無網絡的情況下,打開用戶反饋app,會自動調取本地存儲的文件,這個時候問題就出來了,里面的icon圖片位置有破圖出現,而且點擊進行交互沒有反應,客戶端顯示的h5發起的請求地址居然是本地地址。這兩個bug我是這樣解決的:

1、icon圖片破圖

  當圖片不存在時,出觸發onerror事件,這個時候我們就可以處理一下來讓網頁美觀一些,有兩個方法

  • 讓這個圖片元素隱藏 
    <img src="圖片的url地址" alt="圖片XX" onerror="this.style.display='none'"/>
  • 用默認的圖片替換 
    <img src="圖片的url地址" alt="圖片XX" onerror="this.src='默認圖片的url地址'"/>

我使用的第二種方法,在vue中我們可以這樣使用:

data() {
    return {
         defaultImage: "this.src="+require('./assets/error.png')
     }
}
<img src="圖片的url地址" alt="圖片XX" onerror="defaultImage"/>

2、無網絡狀態下調用客戶端本地的文件,之后打開網絡后,進行頁面交互發起的請求地址不對

使用vue+webpack打包上線的的文件,是需要部署在線上服務器的,能夠以http等協議進行訪問,在項目里面進行api請求,在線上都是以域名進行訪問請求的,比如域名是:https://olqa.faceworld.top/,進行的api請求就是 https://olqa.faceworld.top/api/getCatogryList/lang=zh#/。當使用客戶端本地的文件時,進行的請求訪問地址就變成了 file://XXX/api/getCatogryList/lang=zh#/,這樣的請求交互當然是不生效的。后來服務器開發人員給了我一個建議,讓我寫絕對地址,就是在交互請求的地址上把域名加上去。如下:

      axios({
                    url: 'https://olqa.faceworld.top/olqa/api/faq/getList.do',//把域名加上去
                    params: data,
                    method: 'POST',
                }).then(res => {
                    if(res.status == 200 && res.data.data.length > 0) {
                        this.page ++;
                        this.searchList = this.searchList.concat(res.data.data);
                    }else if(res.status != 200){
                        this.loading = false
                    }else {
                        console.log('沒有結果');
                        this.finished = true;
                    }
                    this.loading = false
                }).catch(err => {
                    console.log('net timeout');
                    this.loading =false;
                })

之后進行打包交給客戶端存儲在本地。這也算是一種解決方法吧。

  任何項目完成上線都不是一帆風順的。這不,測試人員說在低端機上,h5的首屏加載時間有點長,讓我去研究研究改善用戶體驗。vue的SPA頁面都是通過打包后的js文件進行解析后生成dom進行頁面渲染的,如果對於js文件的解析比較慢,是會導致首屏加載時間較長。想着如果進行預渲染,可能會有出奇效果。找到了一款插件:prerender-spa-plugin,

可以把頁面單獨打包出來,而且打包出來的index.html文件可以直接訪問打開,如果放在客戶端本地的話,效果應該不錯。於是就試試:

1、安裝

 npm install prerender-spa-plugin --save-dev

 

 2、webpack.prod.conf.js增加部分代碼

const PrerenderSPAPlugin = require('prerender-spa-plugin')   //引用插件
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
const webpackConfig = merge(baseWebpackConfig, {
    plugins: [
        // vue-cli生成的配置中就已有這個了,不要動
        new HtmlWebpackPlugin({
            filename: config.build.index,
            template: 'index.html',
            inject: true,
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
            },
            chunksSortMode: 'dependency'
        }),
        // 配置PrerenderSPAPlugin
        new PrerenderSPAPlugin({
            // 生成文件的路徑,也可以與webpakc打包的一致。
            staticDir: path.join(__dirname, '../dist'),
            
            // 對應自己的路由文件,比如index有參數,就需要寫成 /index/param1。
            routes: ['/', '/detail','/search'],
           
            // 這個很重要,如果沒有配置這段,也不會進行預編譯
            renderer: new Renderer({
                inject: {
                  foo: 'bar'
                },
                headless: false,
                // 在 main.js 中 document.dispatchEvent(new Event('render-event')),兩者的事件名稱要對應上。
                renderAfterDocumentEvent: 'render-event'
            })
        })
    ]
})

 

 3、在main.js中加入以下代碼

new Vue({
  el: '#app',
  router,
  render: h => h(App),
  mounted () {
    document.dispatchEvent(new Event('render-event'))
  }
})

 

4、使用npm run build打包,dist文件里面有每個路由對應的包 

 

 而且這里面直接打開index.html文件能夠進行訪問。

把這種打包后的文件給了客戶端,確實讓首屏的加載速度上去了。只是這樣打包的文件要比以前打包的文件體積稍大一點,不過綜合比較,覺得這樣的體驗稍好一些,因為都是本地資源,加載速度還是比較快的。

與客戶端合作之旅暫告一段落!

 個人博客地址:https://www.zengfanping.com/

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM