成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

攜程Web組件在跨端場景的實踐

開發 新聞
為了優化此流程,我們引入了一種全新的方案——跨端共享 Web 組件。

作者簡介

Iris,攜程前端開發經理,專注于前端組件庫和工程化領域。

Abert,攜程高級研發經理,關注跨端解決方案。

一、背景

我們在開發 H5 營銷活動后,通常會將營銷活動的入口投放到多端,包括 App、小程序。常見的投放形式有:Native 原生頁面、React Native 頁面和小程序頁面的內嵌彈窗。那么此時,就需要 Native、RN、小程序端的人力投入。由此,整個流程從僅需 H5 開發演變成需要多端開發、溝通,從 H5 營銷活動靈活上線演變成受制于 App 和小程序的版本發布。

為了優化此流程,我們引入了一種全新的方案——跨端共享 Web 組件。這一方案秉承“一套 Web 代碼,多端共享”的理念,旨在縮短上線周期、降低人力成本、并快速響應迭代。采用跨端共享 Web 組件,我們能夠高效地實現多端共享,同時也能夠更加豐富地展示 Web 組件,從而為我們的業務帶來更多的價值。

二、方案介紹

那么如何做到“一套 Web 代碼,多端共享”——

我們的小程序使用 Taro 框架和 React 框架進行開發,Taro 支持渲染 HTML 標簽,鑒于此,我們選擇了 React 作為 Web 組件的開發技術棧,這樣,一方面,我們能直接運行在小程序端,另一方面可以用 React 的強大功能來創建可復用的自定義 HTML 元素。

在小程序端,Web 組件以 NPM 包的形式存在。在 Native 和 RN 端,使用 WebView,加載一個包含 Web Components 的 H5 鏈接。不管是 NPM 包的形式,還是 Web Components 的形式,都是同一套 Web 代碼的產物。

在介紹實踐過程之前,先簡單介紹一下 Web Components。Web Components 是 Web 標準的一部分,是 W3C 提出的一套組件模型。由三個主要技術組成:

a. Custom Elements:允許開發者創建自定義 HTML 元素,這些元素可以擁有自己的屬性和方法。

b. Shadow DOM:允許開發者創建封裝的 DOM 樹,將其附加到自定義元素上,從而實現樣式和行為的隔離。

c.  HTML Templates:允許開發者定義可重用的 HTML 模板,這些模板可以在不同的 Web 應用程序中使用。

瀏覽器基于此標準實現了一套 API,Web Components 作者可以用這些 API 去封裝組件功能,然后把它應用到任何地方,不必擔心有任何沖突。

React 或 Vue 都提供了相應 API,讓開發者能以 React 組件或 Vue 組件的形式書寫 Web Components。而這里,我們正是用的 React 組件的形式書寫 Web 組件,然后將其打包為 Web Components。

假設彈窗組件名為 zt-dialog,我們提供給 Native 和 RN 端的 H5 鏈接內容形似:

<html>

  <head>

    <script src="https://static.tripcdn.com/zt-dialog.umd.js"></script>

  </head>

  <body>

    <zt-dialog></zt-dialog>

  </body>

</html>

這段代碼表明,zt-dialog 組件的自定義 HTML 元素是 `zt-dialog` ,其功能邏輯被打包到一個 UMD 格式的 JavaScript 文件中。這意味著,Web 組件可以被應用到任何其他 H5 中。

我們給小程序端提供的內容則是一個 NPM 包 @ctrip/zt-dialog,主要內容則是:

import Dialog from '@ctrip/zt-dialog'

import '@ctrip/zt-dialog/dist/styles/mini.css'

三、Web組件與宿主環境

我們的 Web 組件相較于普通的 React 組件,需要考慮哪些問題呢?可以從 Web 組件寄宿于不同環境這個角度進行思考,在這個場景下,Native 端、RN 端、小程序端都是宿主環境。

因此我們要思考三個核心問題是:如何識別不同宿主環境,如何使用宿主環境的能力以及如何與宿主環境通信。

3.1 識別宿主環境

其實方法有很多種,比如各端可以傳一個特殊參數,或者利用 WebView 區別于小程序的全局變量等等,來做宿主環境的識別判斷。但最終我們選擇了一種更優解,利用環境變量,在構建時僅打包所需代碼。

環境變量是在應用程序運行時根據不同環境提供不同值的一種機制。我們的 Web 組件使用 Vite 進行構建,它支持在項目中使用環境變量。在應用程序中,通過 `import.meta.env` 對象來訪問這些環境變量,根據值不同,來執行不同的邏輯。在構建時,這些環境變量會被靜態替換。

比如下面這段源代碼,根據`VITE_COMP_TYPE` 變量的值來處理不同的宿主環境下的 onClose 事件和 onJump 事件:

const onClose = () => {

  if (import.meta.env.VITE_COMP_TYPE === 'mini') {

    console.log("mini")

  } else {

    console.log("webview")

  }

});


const onJump = () => {

  if (import.meta.env.VITE_COMP_TYPE === 'mini') {

    console.log("mini jump")

  } else {

    console.log("webview jump")

  }

}

通過這段構建命令:

cross-env VITE_COMP_TYPE=mini vite build

最終小程序端使用的 NPM 包結果輸出如下圖:

const u = () => {

      console.log("mini")

    },

    p = () => {

      console.log("mini jump")

    };

可以看出我們這里只會有`mini` 的代碼。從另一個角度講,小程序端引入 Web 組件,其 Size 是很敏感的,所以我們用這種方式也可以盡可能打包更小 Size 的代碼。

3.2 使用宿主環境的能力

Web 組件需要使用的能力一般來說,有發送請求、導航、分享、埋點。在 Native 和RN 端,我們使用 WebView 加載 Web 組件,那么發送請求,可以利用瀏覽器發送請求的能力;至于埋點,我們也可以使用瀏覽器加載埋點腳本,從而自行處理埋點邏輯;而導航和分享則使用橋方法即可。在小程序端,我們考慮得則要多一些,下面展開講講。

一般來說原生小程序都會對請求進行封裝,帶一些特定的請求參數,并且對請求返回值做預先的處理,因此發送請求只能由小程序端以組件參數的形式傳給 Web 組件。導航、埋點同理。

分享則有一些特殊,微信小程序規定,喚起分享有兩個條件:

條件一:通過給 button 組件設置屬性`open-type=share`;

條件二:在用戶點擊按鈕后觸發`Page.onShareAppMessage`事件獲取到分享相關信息。

條件一經測試,Web 組件用這樣的寫法即可滿足:

<button openType="share">

    <p>分享</p>

</button>

條件二則不行,如果你是小程序開發人員,那么你一定知道`Page.onShareAppMessage`是一個頁面處理函數,它是用于監聽用戶點擊頁面分享按鈕的事件,并不能被主動調用。解決這個問題的思路如下

a. Web 組件從小程序端提供的注冊中心拿到一個唯一分享源 ID

b. Web 組件將分享源 ID 給到 button 標簽

c. Web 組件向分享源信息中心注冊這個 ID 對應的分享信息

最終,用戶在點擊分享的時候,小程序端可從分享源信息中心拿到當前分享源 ID 對應的分享信息。圖示:

圖片

3.3 與宿主環境通信

思考一個問題,Web 組件是否需要與宿主環境通信?如果是,那通信場景有哪些?在實踐過程中,我們發現有這兩種場景:用戶點擊關閉組件、在合適的時機顯示組件。

通信方式如圖:

圖片

就實際場景來看下對應代碼,以“用戶點擊關閉按鈕”場景為例:

const closePopUp = () => {

    if (import.meta.env.VITE_COMP_TYPE === 'mini') {

        props.close(); // 小程序端傳遞的關閉事件參數

    } else if (isRNWebView() {

        window.postMessage(JSON.stringify({

            closeModal: true  // RN端使用postMessage發送closeModal事件

        }));

    } else if (isNativeWebView()) {

        window.Bridge.insideClose(() => {}); // APP端使用橋方法關閉當前WebView

    }

};

由此,不管什么場景下,我們都可以用類似的方式實現與宿主環境的通信。

再看下“在合適的時機顯示組件”這種場景,首先我們理解下什么是“合適的時機”,也許你會想,在符合特定業務邏輯的前提下,讓 Web 組件正常顯示不就是“合適的時機”嗎?實際實踐后,我們發現,在小程序端,我們采用了 NPM 包形式嵌入、打包分離、公共樣式抽離、webp 等方式盡可能優化其性能,Web 組件確實能正常顯示,準確說做到了讓用戶對組件加載無感知。

但是在 Native 和 RN 端,我們使用了 WebView 加載 H5 鏈接的方式,一旦使用了大圖+顯示動畫,那么 Web 組件的呈現方式就有一些不盡如人意,主要體現在用戶能明顯感知到大圖的加載過程、大圖未顯示完成動畫就已經開始。因此,需要把這種場景處理得更細致些。

處理思路如下:

a. Native 加載一個 WebView 容器,此時 WebView 不顯示

b. WebView 加載完成后,加載一個 H5,這個 H5 會加載耗時較多的資源

c. 待資源加載完成后,H5 通知到 Native 顯示 WebView

d. H5 顯示 Web 組件,此時開始 Web 組件的動畫

圖示:

圖片

等資源加載完成后,“通知Native顯示WebView”這個過程則使用橋方法通信機制。

由此,在 Native 和 RN 端,能夠更加細致化地控制 Web 組件的顯示,從而更加優雅地顯示 Web 組件。

至此,Web 組件和宿主環境之間的核心問題就解決了。在這時,我們還在小程序端遇到一個樣式的小問題。Taro 在進行 px 尺寸單位的換算時,默認以 750px 作為換算標準,而我們編寫 Web 組件時,通常以 375px 為標準。這導致在小程序端顯示時,整體樣式會比小程序的樣式小一倍,最后的解決方案是編譯小程序樣式時利用插件對尺寸*2。

另外為了優化圖片加載性能,Web 組件的圖片會使用 webp 格式。在小程序端,支持 webp,因此可以直接使用,而 Native 和 RN 端則需要根據瀏覽器支持情況做一下判斷。

四、對Web組件的支持

在了解了“一套 Web 代碼,多端共享”的正確打開方式之后,再來看下各端對 Web 組件需要做怎樣的支持。畢竟在換位思考之后,我們才能從“旁觀者清”的角度去完善 Web 組件。

首先,Native 端為 Web 組件開啟了一個透明的 WebView。這個 WebView 要區分于非透明的 WebView。因此約定 H5 鏈接里添加特定 query 參數。如果 Web 組件想要指定 WebView 的寬高,也是同樣地添加特定 query 參數。

假設約定的 query 參數是 `insidepop=1`,zt-dialog 組件的 H5 鏈接形式如下:

https://m.ctrip.com/demo/zt-dialog.html?insidepop=1

以 Android 為例,在 Native 端被使用:

Intent intent = new Intent(); // 初始化一個通用Intent

Activity activity = new Activity();

intent.setClass(activity, H5Container.class)

intent.putExtra(H5Container.URL_LOAD, 'https://m.ctrip.com/demo/zt-dialog.html?insidepop=1'); // 加載包含Web組件的H5鏈接

AppUtil.startActivity(activity, intent);

再者,在 RN 端,我們使用 WebView 控件開啟一個透明的 WebView。由于需要處理關閉彈窗、導航、分享等功能,RN 端基于 WebView 控件再次做了封裝。

同樣是 zt-dialog 組件的 H5 鏈接形式,在 RN 端被使用:

import React from 'react';

import { ViewPort, Text, TouchableHighlight } from 'react-native';

import { WebViewModal } from 'react-native-webview';


export default class Demo {

  render() {

    return (

      <ViewPort>

        <TouchableHighlight onPress={() => {this.webviewRef.showModal()}}>

          <Text>show modal</Text>

        </TouchableHighlight>          

        <WebViewModal

          position='bottom'

          webViewUrl={'https://m.ctrip.com/demo/zt-dialog.html'}

        />      

      </ViewPort>

    )

  }

}

最后,小程序端使用的是 NPM 包的形式,基于上述的一些思考,在小程序端,其很多能力都依賴于參數傳遞的方式,因此小程序端封裝了一個 React Hoc 組件,將我們約定好的請求、導航、分享等等能力都封裝到這個 Hoc 組件中。這個 Hoc 組件類似:

import React from "react"

import Taro from "@tarojs/taro"


const webBridgeHoc = (WebComp)=>{

  return (props)=>{

    return <WebComp

      _ubtTrace={_ubtTrace} // 埋點

      _request={requestFunc} // 小程序原生request

      _navigateTo={Taro.navigateTo} // 跳轉

      _redirectTo={Taro.redirectTo} // 重定向跳轉

      _reLaunch={Taro.reLaunch} // 關閉所有頁面,打開到應用內的某個頁面

      _switchTab={Taro.switchTab} // 切換tab頁

      ...

    />

  }

}

export default webBridgeHoc

zt-dialog 組件在小程序端被使用時:

import Dialog from '@ctrip/zt-dialog'

import '@ctrip/zt-dialog/dist/styles/mini.css'

import webBridgeHoc from '@/components/webBridgeHoc'

  
export default webBridgeHoc(Dialog)

總的來說,各端對 Web 組件的支持是相對簡單的。在做了一定的封裝之后,實際應用過程中,我們還在 Native 端的首頁彈窗進一步做了服務端收口下發 Web 組件的 H5 鏈接。因此 Native 端的首頁彈窗甚至無需再有 Native 端的人力介入,也可以完成一個完整閉環的需求交付周期。而這樣的過程是可以完全復制到小程序端和 RN 端的。至此,完全釋放 Native、RN、小程序的人力。

五、總結與展望

其實,從各端對 Web 組件的支持就可以看出,跨端共享 Web 組件一方面是整合了各端現有的能力,另一方面是發揮自己的優勢如豐富的動畫吸引用戶。換句話說,在實踐前期,投入的成本并不大,但初期的效益卻是直觀的——釋放了多端人力,而是否能夠最大化地發揮優勢產生收益則是我們  Web 組件開發需要繼續關注的課題。

后續我們將持續關注,豐富的 Web 組件表現形式是否有效提高了用戶的點擊率以及 Web 組件在各端的性能表現。

最后,讓我們看下 Web 組件的效果:

Native 端:

圖片

小程序端:

圖片

責任編輯:張燕妮 來源: 攜程技術
相關推薦

2022-08-06 08:23:47

云計算公有云廠商成本

2023-07-07 12:26:39

攜程開發

2025-06-24 09:44:41

2014-05-26 16:52:29

移動前端web組件

2022-11-29 20:32:07

2022-07-15 12:58:02

鴻蒙攜程華為

2022-08-03 09:58:03

跨端框架實踐

2022-05-20 11:09:15

Flybirds多端測試UI 自動化測試

2022-05-13 09:27:55

Widget機票業務App

2022-03-30 18:39:51

TiDBHTAPCDP

2022-08-12 08:38:08

攜程小程序Taro跨端解決方案

2023-01-04 12:17:07

開源攜程

2022-08-20 07:46:03

Dynamo攜程數據庫

2022-07-15 09:20:17

性能優化方案

2022-08-12 08:34:32

攜程數據庫上云

2023-02-08 16:34:05

數據庫工具

2022-07-08 09:38:27

攜程酒店Flutter技術跨平臺整合

2022-06-17 09:42:20

開源MMKV攜程機票

2022-06-17 10:44:49

實體鏈接系統旅游AI知識圖譜攜程

2024-04-26 09:38:36

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久久精 | 日本在线播放一区二区 | 久久久av一区 | 亚洲国产成人在线 | 日韩久久久久 | 美女视频.| 亚洲精品9999 | www97影院| 手机av在线 | 在线观看日本网站 | 激情五月激情综合网 | 久久久久久免费毛片精品 | 精品国产99| 欧美xxxⅹ性欧美大片 | 国产精品区二区三区日本 | 午夜激情影院 | 亚洲欧美高清 | 在线观看视频你懂得 | 欧美性video 精品亚洲一区二区 | 91精品国产综合久久福利软件 | 中文字幕免费在线 | 久久午夜剧场 | 亚洲成人久久久 | 日本一二三区高清 | 精品在线观看入口 | 精品久久国产 | 亚洲人精品午夜 | 国产综合av | 欧美日韩在线一区二区 | 亚洲视频在线看 | 亚洲国产欧美日韩 | 91在线视频观看 | 国产精品视频一区二区三区不卡 | 亚洲精品在线免费看 | 国产精品国产三级国产播12软件 | 国产成人精品午夜 | 欧美成人a∨高清免费观看 91伊人 | 91在线影院 | 亚洲欧洲一区二区 | 亚洲日韩中文字幕一区 | 91久久电影 |