項目經驗總結

項目中前端開發問題經驗總結

ie下websocket的安全限制問題

問題描述:
數據看板中的數據大部分都是實時數據或前一天統計的歷史數據,所以這邊後端考慮採用websocket來實時和定時推送數據來保證數據的實時性和有效性。而前端開發這邊爲了提升前端開發的複用性,採用了在各個組件中開發成一個個的小部件,而後在門戶經過vue異步動態加載的方式來實現,小部件的組裝拼接。 所以在組件中開發的小部件都是單vue頁面。所以出現了有幾個小部件就有幾個websocket,目前我這邊就出現了7個websocket。
問題現象:
在ie瀏覽器下,打開時就會發現報錯。IE控制檯會報SecurityError錯誤。
解決方法:
形成上述現象的緣由是ie下websocket鏈接作了安全限制,若是websocket鏈接超過6個時,那麼就會鏈接失敗。默認最大鏈接數爲6個。
那麼如何避免報錯呢?
固然ie下的限制咱們是很差修改的,若是真的強制修改,那麼能夠經過修改註冊表來修改最大鏈接數(固然這邊是不建議的,不可能讓客戶區修改瀏覽器註冊表的)。
那麼咱們須要的就是避免多個websocket的鏈接
2個思路:
使用websocket以前先思考,是否真的有必要使用wesocket??html

  1. 若是是實時推送,定時推送這些場景,那麼徹底沒有必要使用websocket,前端可經過定時器來實現相同的功能。所以能避免使用就避免使用。
  2. 若是是報警等未知的推送,那麼咱們就是必需要使用websocket的,並且若是正好應用在了看板小部件上。那麼仍是會出現7個websocket的狀況。因此這種狀況下就須要和後端溝通,一個項目採用一個websocket服務,經過type來區分。那麼看板就只有一個websocket了。但是如今看板的小部件都是獨立,如何去實現一個websocket?那麼須要藉助一下事件通訊。以下:
a.vue
created () {
    this.$root.eventBus = new Vue()
    this.init()
},
methods: {
    init (i) {
        let ws = new WebSocket()
        ws.onmessage = (data) => {
            this.$root.eventBus.$emit('websocket', data)
        }
    }
}
b.vue
created () {
    this.$root.eventBus.$on('websocket', () => {
        // 處理推送的數據
    })
  }

咱們知道咱們的小部件都是經過在門戶,經過vue動態加載組件的方式來造成看板的,那麼因此小部件就都會在門戶這個vue實例對象下。因此能夠採用this.$root下掛在一個vue實例來實現事件的傳遞前端

備註:
另外若是你一個頁面中只有4個websocket,而認爲ie下就不會報錯,請不要這要處理,也請使用type的形式來處理。由於ie下刷新頁面銷燬websocket是時間延遲的。第一次進入頁面websocket鏈接是正常的,而舒心頁面後,可能就會形成2個websocket鏈接失敗。vue

hui多語言使用問題

問題描述:在使用hui控件的時候,會出現某些bug,而後bug修改後,項目中應用的hui版本也對應的升級。可是這種狀況下,可能會出現hui內置多語言增長了一些字段,致使項目中會出現有未翻譯的字段。
解決方法:node

  1. 在咱們各個組件框架下的i18n下面有一個hui.js文件,這個文件內部就是hui的多語言,這個多語言版本是在腳手架完成的時候就已經建立了,它是不會隨着hui的升級而變化,所以咱們就須要從hui那邊去拿到最新的包(node_modules/hui/lib/locale/lang/zh-CN.js),而後再替換更新。
  2. 固然咱們除了手動這樣替換以外,咱們也能夠直接引用這個文件,那麼以後就不須要再替換了。(固然翻譯的文件仍是須要更具index.json來翻譯最新的)

把hui.js替換成如下代碼那麼中文狀態就能夠隨着hui的升級而變化了webpack

hui.js
修改前:
let hui = {
  colorpicker: {
    confirm: '肯定',
    clear: '清空'
  },
  ....等因此hui的key值
}
export default hui
修改後:
import hui from 'hui/lib/locale/lang/zh-CN.js'
export default hui.el // 這邊是由於hui內部包了一層el,因此直接拋出hui.el的對象

多語言問題的拓展:
在組件中開發中怎麼使用多語言呢?以前組件開發我都是把變量拋到外面,經過調用者傳遞參數進來,那麼外面確定都是已經轉過多語言的了,那麼這種確定是沒問題的,固然這不是特別好的。所以這邊把hui-pro如何使用多語言的方式來講明一下,之後開發組件中遇到多語言問題均可以這樣操做,向hui那樣把語言放到項目工程中。web

首先在工程中須要建立對應的語言js文件如zh_CN.js
而後在建立一個調用的方式:ajax

import defaultLang from 'hui-pro/src/locale/lang/zh-CN';
import Vue from 'vue';
import deepmerge from 'deepmerge';
import Format from './format';

const format = Format(Vue);
let lang = defaultLang;
let merged = false;
let i18nHandler = function() {
  const vuei18n = Object.getPrototypeOf(this || Vue).$t;
  if (typeof vuei18n === 'function' && !!Vue.locale) {
    if (!merged) {
      merged = true;
      Vue.locale(
        Vue.config.lang,
        deepmerge(lang, Vue.locale(Vue.config.lang) || {}, { clone: true })
      );
    }
    return vuei18n.apply(this, arguments);
  }
};

export const t = function(path, options) {
  let value = i18nHandler.apply(this, arguments);
  if (value !== null && value !== undefined) return value;

  const array = path.split('.');
  let current = lang;

  for (let i = 0, j = array.length; i < j; i++) {
    const property = array[i];
    value = current[property];
    if (i === j - 1) return format(value, options);
    if (!value) return '';
    current = value;
  }
  return '';
};

export const use = function(l) {
  lang = l || lang;
};

export const i18n = function(fn) {
  i18nHandler = fn || i18nHandler;
};

export default { use, t, i18n };

這個js文件是用於合併工程中的多語言或本身翻譯t函數就是對外組件使用多語言的方法。
這邊經過作一個mixinsjson

import { t } from 'hui-pro/src/locale';

export default {
  methods: {
    t(...args) {
      return t.apply(this, args);
    }
  }
};

而後直接在組件中使用該mixins便可後端

<template>
   {{ t(`h.common.add`) }}
</template>
import Locale from 'hui-pro/src/mixins/locale';
export default {
   mixins: [Locale]
}

require的使用問題

問題描述: 目前這邊有那麼一種場景,前端有一些列的城市的json文件,而前端須要根據後端的返回值來調用相應的城市json文件。對於這種狀況下:我就使用了require加載動態文件的方式來加載,由於require是同步加載的,因此比較方便。使用方式以下瀏覽器

let city 從後端獲取
let cityMap = require(`static/city/${city}.json`);
// 後續根據cityMap再處理

就以上那麼一段代碼在打包的時候會將city下的因此json文件都打包的js裏面。(require是提早把全部的文件都打包進來,才使得能夠動態的加載)。
形成了js比原來臃腫了不少。(臃腫程度是跟city下json文件大小有關)。而後進入對應的頁面也會相對要慢一些(js比原先大了一些),這樣用戶體驗很差。
由於對於動態加載的方式儘可能避免(若是文件小的話,那影響不大)
解決方法:
動態獲取的文件(這邊的city.js,多語言,皮膚包等等)儘可能都經過ajax來獲取,這樣打包的js文件會少不少。
爲了保證還是同步的,那麼就採用es7的async、await來操做吧

async get () {
    let city = xxx
    try {
        let cityMap = await xxx.get('xxxx')
        // 在根據cityMap出咯
    } catch {}
}

門戶看板小部件打包的一些問題

問題描述:以前講述了一篇關於如何打包小部件的,可是那篇並無使用複雜的頁面,引用第三方插件等。就是單純幾個簡單的頁面的測試。這一次實際打包以後發現仍然有很多問題須要優化:

  1. 打包的文件會比較大。這是因爲每一個單vue文件打包,將全部依賴都打包進來了,那麼就形成文件過於臃腫,相比於單vue實例的效果會差不少,會重複打包vue,hui,echarts等一些插件。

所以這邊須要剔除依賴進行打包,方法以下:

// webpack配置中增長以下配置項,如還有其餘第三方插件均可以配置在以下
externals: {
    echarts: 'echarts',
    hui: 'hui',
    vue: 'vue'
},

經過以上過濾,能夠講一個文件從幾M縮小到100KB之內。

  1. 小部件中沒法獲取到本身組建內部的多語言。

a. 這個是因爲小部件內部是經過this.$t的形式去調用i18n來翻譯的。可小部件的環境發生了變化,經過門戶動態調用組件的方式加載,那麼小部件所在的環境就是門戶的vue實例對象,那麼i18n也就是門戶的,因此小部件就沒法獲得翻譯。
b. http的實例對象內部也不能夠經過i18n以及{message} from 'hui'這些。緣由是已經剔除了這些依賴,那麼打包後就會報錯,i18n和hui不存在。
解決方法: 經過一個配置文件裏面存放本身組件中的i18n的json文件路徑(/oams/static/i18n/zh-CN/index.json),以及一個keys字段。將看板的部件多語言文件給讓門戶下載,並跟門戶本身的多語言合併(所以多語言key必定要加上本身的上下文或其餘來和門戶區分,不要字段重疊)。這些組件內部經過this.$t也都能正常翻譯。

hui上傳組件的問題

問題描述: 目前前端都使用了統一的前端請求封裝,http都作了一些處理如登陸過時跳登錄頁,可上傳組件是組件內部本身ajax請求,所以是不會作這些特殊處理。所以在組件內部須要本身作一下
解決方法:
若是當前已經登陸過時,那麼後端單點登陸針對Content-Type爲application/json都是後端作了一層處理,返回errorCode爲pleaseRefreshByHeader,那麼前端根據這個值來跳登陸頁。但是上傳組件的Content-Type:multipart/form-data,這種類型的單點登陸是直接進行攔截而不會通過後端,直接返回錯誤頁面。
那麼咱們就須要針對返回的頁面作特殊處理

uploadSuccess (res, file) {
      if (res.code === '0') {
        this.$message.success(this.$t(`oams_common.addSuccess`))
        this.addMapDialog = false
        this.$emit('add-map-success')
      } else {
      // 頁面過時處理
        if (res.includes && res.includes('html')) {
          let refreshUrl = '/isecure/cas/login?service=' + location.protocol + '//' + location.host + location.pathname
          location.href = refreshUrl
        } else {
        // 錯誤碼處理
          this.$message.error(this.$t(`oams_errorcode.${res.code}`))
          this.$refs.mapUpload.clearFiles()
          this.$nextTick(() => {
            this.mapForm.filename = ''
          })
        }
      }
    }

除了上面的方法還能夠在上傳組件前,先本身發送一個接口驗證當前頁面是否已通過期,若是已通過期,那麼它就會自動跳轉首頁了(本身的接口都是通過處理的),並且這也不僅僅處理了單點登陸,網絡超時也作了相應了處理。(上傳組件是沒有作超時處理的,由於不知道文件上傳須要多久,若是設置了,網絡差的狀況下可能上傳文件或圖片就失敗了)

相關文章
相關標籤/搜索