成品直播原始碼,大屏元素解析度適配的常用方案

云豹科技-苏凌霄發表於2024-03-09

越來越多的客戶喜歡在成品直播原始碼中新增一個或者多個視覺化大屏,用來集中的展現資料變化、位置變化等等。作為程式設計師在完成該需求時,經常會有這樣的問題:我有一個大屏的模板,但是使用者的瀏覽器解析度不夠,或者有的有書籤欄有的沒有書籤欄,更或者是有的全屏了有的只是小視窗,這樣就有了程式碼對不同解析度場景下的適配需求了。

成品直播原始碼開發時常用的適配方案

平時我們使用的 web 端的適配方案,主要有以下幾種:

1、vw/vh 配合百分比實現,讓元素根據視窗大小進行自動調整
2、fontSize 配合 rem 實現“單位寬度”的統一
3、根據不同的解析度範圍調整頁面佈局
4、版心佈局,配合最小寬度

目前大多數螢幕適配方案的原理都是採用的以上的幾種方式,但是這幾種方式也有很大的弊端:瀏覽器文字有最小尺寸!
在一般的 1080p 及以上的解析度的螢幕中,大多數設計圖的比例和顯示效果都能完美還原。但如果成品直播原始碼中某個系統的頁面內容太多,或者瀏覽器部分使用的解析度(不是物理解析度)達不到完整顯示的要求,採用上面的幾種方式就有可能造成 文字的計算大小小於瀏覽器的最小字型大小,此時就有可能因為文字寬度超出元素而導致頁面樣式崩潰。

版心佈局配合最小寬度可以保證顯示效果,但是不適合大屏專案。

CSS3 縮放方案

在上面的幾種方案都不滿足時,大家一般就會採用另外一種方案:CSS3 scale 縮放。
透過計算設計圖尺寸比例與成品直播原始碼實際的頁面顯示區域大小,來動態調整元素的縮放比例。

個人認為這是針對小解析度情況下保留顯示內容及樣式最好的一種處理方式。

當然,這種方式依然有一些弊端:

1、縮放後可能會造成邊緣顯示模糊
2、如果內部存在 canvas 元素,可能導致 canvas 內部的內容渲染失真

封裝一個縮放指令

這裡簡單回顧一下 Vue 的自定義指令:透過配置自定義指令和繫結引數,在元件/元素載入、更新、銷燬等不同時期執行對應的處理邏輯。
Vue 的自定義指令包含一下幾個鉤子函式:

bind: 解析到指令繫結時執行,僅執行一次
inserted: 插入父節點時執行
update:元件觸發更新時執行
componentUpdated:所有元件更新結束之後執行
unbind:元素解綁(銷燬)時執行,也只執行一次

這裡因為我們只需要在初始化時繫結瀏覽器的 resize 事件來調整元素縮放,所以只需要配置 inserted 即可;當然,為了最佳化成品直播原始碼邏輯,減少資源消耗等情況,也需要在 unbind 階段去取消 resize 事件的一個回撥函式。
程式碼如下:

// 縮放指令
import Vue from "vue";

function transformScale(el, options) {
  const { target = "width", origin = "top left" } = options;

  Vue.nextTick(() => {
    // 獲取顯示區域高寬
    const width = window.innerWidth;
    const height = window.innerHeight;
    el.style.transformOrigin = origin;
    if (target === "ratio") {
      const scaleX = width / CONF.width;
      const scaleY = height / CONF.height;
      el.style.transform = `scaleX(${scaleX}) scaleY(${scaleY})`;
    } else {
      let scaleProportion = 1;
      if (target === "width") {
        scaleProportion = width / CONF.width;
      }
      if (target === "height") {
        scaleProportion = height / CONF.height;
      }
      el.style.transform = `scale(${scaleProportion})`;
    }
  });
}

function inserted(el, binding) {
  const options = binding.options || { passive: true };

  const callback = () => transformScale(el, binding.value);

  window.addEventListener("resize", callback);

  callback();

  el._onResize = {
    callback,
    options
  };
}

function unbind(el) {
  if (!el._onResize) {
    return;
  }

  const { callback } = el._onResize;
  window.removeEventListener("resize", callback);
  delete el._onResize;
}

export const Scale = {
  inserted,
  unbind
};

export default Scale;

說明:

1、指令接收一個物件引數,用來指定比例計算方式和縮放定位
2、需要一個全域性配置 CONF 物件,用來指定預設的頁面尺寸
3、為了保證頁面已經載入完,能獲取到 dom 元素,需要呼叫 Vue.nextTick
4、需要銷燬監聽事件

整個程式碼其實很簡單,就是透過監聽 resize 事件去調整元素的縮放比例。
但是這裡我也做了一點小的配置,用來適應成品直播原始碼中更多的情況:

1、接收一個 target 配置,用來確認比例計算方式;可以以寬度或者高度作為統一的縮放標準,也可以分別計算
2、接收 transform 的 origin 配置,保證不同位置的元素可以縮放到不同的位置,避免縮放偏移
3、不涉及繫結元素的尺寸,只需要預設尺寸即可;寫程式碼時可以直接根據設計圖配置元素尺寸

後記

當然,這個指令應用於成品直播原始碼不能說有多完美,依然有很多有漏洞的地方,比如沒有防抖、縮放不會改變css指定的尺寸,容易出現捲軸等;並且因為之前的專案中還涉及到很多圖表、地圖,也經常導致一些顯示問題,所以後面有增加了一些新的指令,但是解析度適配這個問題還是要根據實際情況來確定具體的方案。

以上就是成品直播原始碼,大屏元素解析度適配的常用方案, 更多內容歡迎關注之後的文章

相關文章