整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          你了解 JSX,那你了解 StyleX 么?

          家好,我卡頌。

          近日,Meta開源了一款「CSS-in-JS庫」 —— StyleX。看命名方式,Style - X是不是有點像JS - X,他們有關系么?當然有。

          JSX是一種「用JS描述HTML」的語法規范,廣泛應用于前端框架中(比如ReactSolidJS...),由Meta公司提出。

          同樣的,按照Meta的設想,StyleX是一種「用JS描述CSS」的語法規范。

          早在React Conf 2019[1]Meta工程師「Frank」就介紹了這種Meta內部使用的「CSS-in-JS庫」

          Meta內部使用,到大會對外宣傳,這期間肯定已經經歷大量內部項目的洗禮。而從做完宣傳到最終開源,又經歷了快5年時間。

          那么,這款Meta出品、打磨這么長時間的「CSS-in-JS庫」,到底有什么特點呢?

          本文讓我們來聊聊。

          為什么需要CSS解決方案

          市面上有非常多「CSS解決方案」,比如:

          • BEM命名規范
          • CSS Module規范
          • 原子CSS(比如TailwindCSS
          • CSS-in-JS(比如emotion

          為什么需要這些方案?原生CSS哪里不好?在這里,我們舉個小例子(例子來源于「React Conf 2019」)。考慮如下代碼:

          CSS文件如下:

          .blue {color: blue;}
          .red {color: red;}
          

          HTML文件如下:

          <p class="red blue">我是什么顏色?</p>
          

          請問p標簽是什么顏色的?

          class來看,bluered后面,p應該是藍色的么?

          實際上,樣式取決于他們在樣式表中定義的順序,.red的定義在.blue后面,所以p應該是紅色的。

          是不是已經有點暈了?再增加點難度。如果.red.blue分別在兩個文件中定義呢?

          # css文件1
          .blue {color: blue;}
          
          # css文件2
          .red {color: red;}
          

          p的樣式就取決于最終打包代碼中樣式文件的加載順序。

          上面只是原生CSS「選擇器優先級相關的一個缺陷」(除此外還有其他缺陷,比如「作用域缺失」...)。隨著項目體積增大、項目維護時間變長、項目維護人員更迭,這些缺陷會被逐漸放大。

          正是由于這些原因,才出現了各種「CSS解決方案」

          StyleX的基本使用

          StyleXAPI很少,掌握下面兩個就能上手使用:

          • stylex.create,創建樣式
          • stylex.props,定義props

          比如:

          import * as stylex from 'stylex';
          
          // 創建樣式
          const styles = stylex.create({
            red: {color: 'red'},
          });
          
          // 定義props
          const redStyleProps = stylex.props(styles.red);
          

          使用時:

          <div {...redStyleProps}>文字顏色是紅色</div>
          

          stylex是如何解決上面提到的red blue優先級問題呢?其實很簡單,考慮如下代碼:

          import * as stylex from 'stylex';
          
          // 創建樣式
          const styles = stylex.create({
            red: {color: 'red'},
            blue: {color: 'blue'}
          });
          
          // 使用
          <p {...styles.props(styles.red, styles.blue)}></p>
          

          樣式的優先級只需要考慮styles.props中的定義順序(bluered后面,所以顏色為blue),不需要考慮樣式表的存在。

          有些同學會說,看起來和常見的CSS-in-JS沒啥區別啊。那stylex相比于他們的優勢是啥呢?

          相比其他CSS-in-JS的優勢

          首先要明確,stylex雖然以CSS-in-JS的形式存在,但本質上他是一種「用JS描述CSS的規范」。文章開頭也提到,他的定位類似JSX

          既然是規范,那他就不是對CSS的簡單封裝、增強,而是一套「自定義的樣式編寫規范」,只不過這套規范最終會被編譯為CSS

          作為對比,LessSass這樣的「CSS預處理器」就是對CSS語法的封裝、增強

          那么,stylex都有哪些規范呢?

          比如,stylex鼓勵將樣式與組件寫在同一個文件,類似VueSFC(單文件組件)。這么做除了讓組件的樣式與邏輯更方便維護,也減少了stylex編譯的實現難度。

          再比如,CSS中各種選擇器的復雜組合增強了選擇器的靈活性。但同時也增強了不確定性。舉個例子,考慮如下三個選擇器:

          • .className > *
          • .className ~ *
          • .className:hover > div:first-child

          這些對.className應用的選擇器將影響.className的某些后代。當這樣的選擇器多了后,很可能會在開發者不知道的情況下改變某些后代元素的樣式。

          遇到這種情況我們一般會怎么處理呢?正確的選擇當然是找到上述影響后代的選擇器,再修改他。

          但大家工作都這么忙,遇到這種問題,多半就是用新的選擇器覆寫樣式,必要的時候還會加!important后綴。久而久之,這代碼就沒法維護了。

          為了規避這種情況,在stylex中,除了「可繼承樣式」(指「當父元素應用后,子孫元素默認會繼承的樣式」,比如color)外,不支持這些「可以改變子孫后代樣式的選擇器」

          那我該如何讓子孫組件獲得父組件同樣的樣式呢?通過props透傳啊~

          也就是說,stylex禁用了CSS中可能造成混淆的選擇器,用JS的靈活性彌補這部分功能的缺失。

          有些同學可能會說:這些功能,其他「CSS-in-JS庫」也能做啊。

          這就要談到「CSS-in-JS庫」最大的劣勢 —— 為了計算出最終樣式,在運行時會造成額外的樣式計算開銷。

          stylex通過編譯來減少運行時的開銷。比如對于上面提到過的stylex的代碼:

          import * as stylex from 'stylex';
          
          // 創建樣式
          const styles = stylex.create({
            red: {color: 'red'},
          });
          
          // 定義props
          const redStyleProps = stylex.props(styles.red);
          

          編譯后的產物包括如下兩部分:

          JS的編譯產物:

          import * as stylex from 'stylex';
          const redStyleProps = {className: 'x1e2nbdu'};
          

          CSS的編譯產物:

          .x1e2nbdu {
            color: red;
          }
          

          所以,運行時實際運行的代碼始終為:

          <div {...{className: 'x1e2nbdu'}}>...</div>
          

          對于再復雜的樣式,stylex都會通過編譯生成「可復用的原子類名」

          即使是跨文件使用樣式,比如我們在另一個文件也定義個使用color: 'red'樣式的stylex屬性foo

          import * as stylex from '@stylexjs/stylex';
          
          const styles = stylex.create({
            foo: {
              color: 'red',
            },
            bar: {
              backgroundColor: 'blue',
            },
          });
          

          會得到如下編譯結果,其中x1e2nbdu是一個原子類名,他是上一個文件中styles.red的編譯產物:

          import * as stylex from '@stylexjs/stylex';
          
          const styles = {
            foo: {
              color: 'x1e2nbdu',
              $$css: true,
            },
            bar: {
              backgroundColor: 'x1t391ir',
              $$css: true,
            },
          };
          

          隨著項目體積增大,樣式表的體積也能控制在合理的范圍內。這種對原子類名的控制粒度是其他「CSS-in-JS庫」辦不到的。

          相比于原子CSS的優勢

          stylex相比TailwindCSS這樣的原子CSS有什么優勢呢?

          這就要談到原子CSS的一個特點 —— 使用約定好的字符串實現樣式。比如,使用TailwindCSS定義圖片的樣式:

          <img class="w-24 h-24 rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">
          

          效果如下:

          由于樣式都是由不同的「原子類名字符串」組合而成,TS沒法分析,這就沒法實現「樣式的類型安全」

          什么叫「樣式的類型安全」?通俗的講,如果我實現一個組件,組件通過style props定義樣式,我只希望使用者能夠改變colorfontSize兩個樣式屬性,不能修改其他屬性。如果能實現這一點,就是「樣式的類型安全」

          「樣式的類型安全」有什么意義呢?舉個例子:設想開發基礎組件庫的團隊使用stylex。那么當業務團隊使用該組件庫時,就只能自定義組件的一些樣式(由組件庫團隊約束)。

          當基礎組件庫升級時,組件庫團隊能很好對組件樣式向下兼容(因為知道只有哪些樣式允許被修改)。

          stylex中,由于stylex.create的產物本質是對象,所以我們可以為每個產物定義類型聲明。比如在如下代碼中,我們限制了組件style props只能接受如下stylex樣式

          import type {StyleXStyles} from '@stylexjs/stylex';
          
          type Props = {
            // ...
            style?: StyleXStyles<{
              color?: string;
              backgroundColor?: string;
              borderColor?: string;
              borderTopColor?: string;
              borderEndColor?: string;
              borderBottomColor?: string;
              borderStartColor?: string;
            }>;
          };
          

          總結

          我猜想,當更多人知道stylex后,他會收到比當初TailwindCSS火時更多的兩級分化的評價。

          畢竟,stylex的設計初衷是為了解決Meta內部復雜應用的樣式管理。如果:

          • 你項目沒有達到Meta這樣的體量
          • 你項目沒有多年的迭代周期
          • 你項目前前后后沒有多個工程師經手

          那大概率是不能接受stylex設計理念中的這些約束。

          對于stylex,你怎么看?

          參考資料

          [1]

          React Conf 2019: https://www.youtube.com/watch?v=9JZHodNR184&t=270s

          前端開發中,Vue 一直以其簡單、高效的框架而備受開發者青睞。然而,隨著 React 在市場上的流行,許多開發者開始對 JSX(JavaScript XML)這種聲明式編程風格產生興趣。本文將探討 JSX 在 Vue3 中的應用,并對其是否成為 Vue3 前端開發的未來進行論證。

          Vue3與JSX的愛恨情仇

          在開始之前,我們先來了解一下 Vue 本身的模版語法和 JSX 分別是什么。

          Vue3模版語法

          Vue3 模版語法是 Vue.js 中常用的一種聲明式模板語法,使用 HTML 語法來描述視圖。在模板語法中,可以通過插值、指令和事件綁定等方式來將數據與視圖關聯起來。這是其簡單易用和上手快的主要原因之一。

          <template>
            <div>
              <h1>{{ title }}</h1>
              <p v-if="showText">{{ text }}</p>
              <ul>
                <li v-for="item in list" :key="item.id">{{ item.name }}</li>
              </ul>
            </div>
          </template>
          
          <script>
          export default {
            data() {
              return {
                title: 'Vue3 Template Syntax',
                text: 'This is a demo text.',
                showText: true,
                list: [
                  { id: 1, name: 'Item 1' },
                  { id: 2, name: 'Item 2' },
                  { id: 3, name: 'Item 3' },
                ],
              };
            },
          };
          </script>
          

          Vue3 的模板語法使用雙花括號({{ }})進行數據插值,使用v-ifv-for等指令處理條件和循環邏輯。

          什么是JSX?

          JSX 是一種 JavaScript 的語法擴展,它允許在 JavaScript 代碼中編寫類似于 XML 的結構。React 是第一個廣泛使用 JSX 的框架,它將組件的結構和邏輯封裝在 JSX 中,用于描述 UI 組件的層次結構。隨著 React 的成功,也隨著時間的推移,JSX 逐漸成為了一種通用的模式,被許多其他框架和庫所采用支持。

          React示例:

          import React, { useState } from 'react';
          
          function JSXComponent() {
            const [title, setTitle] = useState('JSX in React');
            const [showText, setShowText] = useState(true);
            const list = [
              { id: 1, name: 'Item 1' },
              { id: 2, name: 'Item 2' },
              { id: 3, name: 'Item 3' },
            ];
          
            return (
              <div>
                <h1>{title}</h1>
                {showText && <p>This is a demo text.</p>}
                <ul>
                  {list.map((item) => (
                    <li key={item.id}>{item.name}</li>
                  ))}
                </ul>
              </div>
            );
          }
          
          export default JSXComponent;
          

          Vue3示例:

          import { defineComponent, ref } from 'vue';
          
          const JSXComponent = defineComponent({
            setup() {
              const title = ref('JSX in Vue3');
              const showText = ref(true);
              const list = [
                { id: 1, name: 'Item 1' },
                { id: 2, name: 'Item 2' },
                { id: 3, name: 'Item 3' },
              ];
          
              return {
                title,
                showText,
                list,
              };
            },
            render() {
              return (
                <div>
                  <h1>{this.title}</h1>
                  {this.showText && <p>This is a demo text.</p>}
                  <ul>
                    {this.list.map((item) => (
                      <li key={item.id}>{item.name}</li>
                    ))}
                  </ul>
                </div>
              );
            },
          });
          
          export default JSXComponent;
          

          從上面不難看出,在 JSX 中,我們可以直接使用 JavaScript 表達式(如{title}),也可以使用條件語句(如{showText && <p>This is a demo text.</p>})和數組的map方法來處理循環邏輯。

          這些只是舉例,有很多的 JavaScript 語法和方法等,都可以在這里使用。總之,使用 JSX 開發,可以很大程度上利用好 JavaScript,開發更加方便。

          如何配置JSX?

          在 Vue3 中,我們可以通過 Vue 官方提供的項目腳手架工具 create-vue 來新建一個支持JSX的項目。首先,確保你安裝了最新版本的 Node.js(我用的是 16+ 版本),然后執行以下命令:

          npm init vue@latest
          

          這個命令將會安裝并執行 create-vue 工具。在執行過程中,你會看到一些可選的功能配置提示,其中會有如下內容:

          Vue.js - The Progressive JavaScript Framework
          
          ? Project name: … vue-project
          ? Add TypeScript? … No / Yes
          ? Add JSX Support? … No / Yes
          ? Add Vue Router for Single Page Application development? … No / Yes
          ? Add Pinia for state management? … No / Yes
          ? Add Vitest for Unit Testing? … No / Yes
          ? Add an End-to-End Testing Solution? ? No
          ? Add ESLint for code quality? … No / Yes
          ? Add Prettier for code formatting? … No / Yes
          
          Scaffolding project in ...
          

          執行到? Add JSX Support?時選擇Yes,這樣 JSX 就會自動安裝。如果不確定是否要開啟某個功能,你可以直接按下回車鍵選擇 No

          當然,你也可以在已有的Vue項目中配置JSX。

          在已有項目中配置JSX,首先需要安裝相關依賴:

          npm install --save-dev @vue/babel-plugin-jsx
          

          然后,在項目的vite.config.ts文件中進行配置。具體的配置內容如下圖所示:

          image.png

          配置完成后,現在我們就可以在項目中使用 JSX 語法來開發了。這樣,我們可以根據具體的場景選擇使用 Vue 模板或 JSX 語法。

          總的來說,配置 JSX 是非常簡單的,通過上述步驟,我們可以輕松地在 Vue 項目中使用 JSX,發揮其簡潔、易讀的優勢,讓我們的代碼更加優雅和高效。

          模板語法 vs JSX

          現在,我們來對比一些具體的代碼示例,看看 Vue3 模板語法和 JSX 之間的差異。

          1000.webp

          1.數據插值

          Vue3 模板語法使用雙花括號{{}}進行數據插值,而 JSX 使用花括號{}

          模板示例:

          <template>
            <p>{{ message }}</p>
          </template>
          
          <script>
          import { ref } from 'vue';
          
          export default {
            setup() {
              const message = ref('Hello, JSX!');
              return { message };
            },
          };
          </script>
          

          JSX示例:

          import { defineComponent } from 'vue'; 
          
          const DynamicData = defineComponent({
            setup() {
              const message = ref('Hello, JSX!');
              return { message };
            },
            render() {
              return <p>{this.message}</p>;
            },
          });

          2.條件渲染

          在 Vue3 中,我們可以使用v-if指令進行條件渲染,而在 JSX 中,我們使用 JavaScript 的條件表達式。

          模板示例:

          <template>
            <div>
              <p v-if="showContent">Content is visible.</p>
              <p v-else>Content is hidden.</p>
              <button @click="toggleContent">Toggle</button>
            </div>
          </template>
          
          <script>
          import { ref } from 'vue';
          
          export default {
            setup() {
              const showContent = ref(true);
          
              function toggleContent() {
                showContent.value = !showContent.value;
              }
          
              return { showContent, toggleContent };
            },
          };
          </script>
          

          JSX示例:

          import { defineComponent } from 'vue'; 
          
          const ConditionalRender = defineComponent({
            setup() {
              const showContent = ref(true);
              return { showContent };
            },
            render() {
              return (
                <div>
                  {this.showContent ? <p>Content is visible.</p> : <p>Content is hidden.</p>}
                  <button onClick={() => this.showContent = !this.showContent}>Toggle</button>
                </div>
              );
            },
          }};

          3.列表渲染

          在 Vue3 中,我們使用v-for指令來處理列表渲染,而在 JSX 中,我們使用 JavaScript 的map方法。

          模板示例:

          <template>
            <ul>
              <li v-for="item in items" :key="item">{{ item }}</li>
            </ul>
          </template>
          
          <script>
          import { ref } from 'vue';
          
          export default {
            setup() {
              const items = ref(['Apple', 'Banana', 'Orange']);
              return { items };
            },
          };
          </script>
          

          JSX示例:

          import { defineComponent } from 'vue'; 
          
          const ListRendering = defineComponent({
            setup() {
              const items = ref(['Apple', 'Banana', 'Orange']);
              return { items };
            },
            render() {
              return (
                <ul>
                  {this.items.map(item => (
                    <li key={item}>{item}</li>
                  ))}
                </ul>
              );
            },
          });
          

          模板語法和JSX的優劣勢

          接下來,我們將對 Vue 模板和 JSX 進行對比,從多個方面分析它們的優勢與劣勢。

          a. 語法簡潔性

          Vue 模板使用 HTML 語法,更加接近常規 HTML 結構,因此對于前端開發者來說比較容易上手。然而,「隨著項目的復雜性增加,模板中可能會包含大量的指令和插值,導致代碼變得冗長。」 例如,條件渲染、循環遍歷等情況都需要使用 Vue 特定的指令。「相比之下,JSX 在 JavaScript 語法的基礎上,使用類似 XML 的結構,使得代碼更加緊湊和直觀。」

          模板示例:

          <template>
            <div>
              <h1 v-if="showTitle">{{ title }}</h1>
              <ul>
                <li v-for="item in items" :key="item.id">{{ item.name }}</li>
              </ul>
            </div>
          </template>
          

          JSX示例:

          const MyComponent = () => {
            return (
              <div>
                {showTitle && <h1>{title}</h1>}
                <ul>
                  {items.map(item => (
                    <li key={item.id}>{item.name}</li>
                  ))}
                </ul>
              </div>
            );
          };
          

          從上面的對比可以看出,JSX語法更加簡潔,尤其在條件渲染循環遍歷方面更加靈活。

          b. 組件化開發

          Vue.js 本身就支持組件化開發,但是在 Vue 模板中,組件的定義與使用是通過特定的 HTML 標簽和 Vue 指令實現的。這種方式雖然簡單易懂,但是在代碼重用和維護方面可能會有一些限制。相比之下,JSX 在 React 中的組件化開發非常強大,組件可以直接在 JavaScript 中定義,并且支持更加靈活的組合方式。

          模板示例:

          <template>
            <div>
              <my-component :prop1="value1" :prop2="value2" />
            </div>
          </template>
          

          JSX示例:

          const MyComponentWrapper = () => {
            return (
              <div>
                <MyComponent prop1={value1} prop2={value2} />
              </div>
            );
          };
          

          從上面的對比可以看出,JSX 允許在JavaScript中直接定義組件,并且組件的傳參更加直觀。

          c. 類型檢查與IDE支持

          由于 Vue 模板使用了特定的指令和 HTML 語法,IDE 對于代碼的支持可能相對有限。而 JSX 是 JavaScript 的擴展語法,因此可以與類型檢查工具(如TypeScript)完美結合,同時得到更好的 IDE 支持,例如自動補全、代碼跳轉等。

          d. 可擴展性

          Vue 模板的語法是固定的,不能隨意擴展。而 JSX 作為 JavaScript 的一部分,不需要額外的指令或語法,可以通過編寫函數和組件來擴展其語法,也使得處理邏輯、計算和條件渲染變得更加靈活和方便。

          e.生態系統的互通性

          JSX 作為 React 的核心特性,擁有龐大的社區和豐富的生態系統,為開發者提供了海量的工具和庫。

          同時 JSX 在多個框架中得到了廣泛支持,開發者們可以更輕松地在不同的項目和技術棧之間切換,而無需學習不同的模板語法。如文章上面“如何配置JSX?”中對已有項目的配置,將 JSX 作為插件寫到 Vue Plugin 即可配置完成。

          模板語法和JSX的適用場景

          Vue3 的模板語法和 JSX 各有優劣,因此它們在不同的場景下有不同的適用性。

          模板語法的適用場景

          • 快速原型開發:對于快速構建原型或小型項目,Vue3 的模板語法非常適合,可以快速上手和開發。
          • HTML/CSS開發者:對于更擅長 HTML/CSS 的開發者,Vue3 的模板語法更加親切。

          JSX的適用場景

          • 復雜交互:對于具有復雜交互邏輯的項目,使用 JSX 可以更靈活地處理各種條件和事件。
          • React生態系統:如果項目需要使用豐富的 React 生態系統,或者團隊已經熟悉了 React 和 JSX,那么繼續使用 JSX 是合理的選擇。

          總結

          無論是從開發體驗、技術生態還是未來趨勢來看,JSX它使得組件的模板結構更加清晰、聲明性,提供了更強大的 JavaScript 表達能力,同時也增強了與其他技術棧的互通性。雖然傳統的 Vue2 模板語法在一定程度上仍然適用,但通過引入 JSX,Vue3 在前端開發領域擁有更廣闊的發展前景。開發者們可以更加便利地構建復雜的交互界面,同時又能享受到 Vue3 帶來的性能優勢。

          線程前端框架:Voe.js

          看一眼 API,乍一看仿佛和 fard 類似的 API,仿佛又寫了個跨端小程序框架?

          然而并不是……

          voe 是一個底層小程序框架

          意思是它實現了小程序的雙線程,利用“沙箱” 隔離 web 環境,屏蔽 dom 能力

          接下來結合 微信小程序 介紹一下主要思路:

          目標

          絕對的控制力,意思是用戶不能操作 dom,不能使用 web API,不能使用完整的 jsx 和 html,不能……反正就是啥都不能!

          就好像 sm 角色一樣,s 對 m 的絕對控制與虐待,m 只能服從命令與受虐

          所以我把小程序的雙線程架構又稱為 【主奴架構】

          沙箱

          小程序中不能操作 dom,不是因為它屏蔽了 dom API 或者屏蔽了事件,這樣做是不切實際的

          大家都是尋找一個非 dom 環境作為沙箱,比如 v8,比如 worker,比如 native,比如 wasm

          以上都是 OK 的,我猜微信小程序等也是用的類似的沙箱

          voe 使用 web worker 作為沙箱

          為什么不使用 v8 或 native?

          這就是純粹的個人選擇了,不選擇 v8 或 native 應該是,但是偏偏我個人更偏前一點,web worker 的計算力默認是優于 v8 或 native 的(同等硬件水平),但是 v8 也有好處,比如 node 可以使用 cookie,然后擁有一些先進的 API

          將框架拆到兩個不同的線程中

          重點來了,兩個線程中,如何安排框架工作呢?

          有幾個原則:

          1. 用戶邏輯必須跑在 worker 中,完全不讓碰 主線程
          2. 計算力的邏輯盡可能多的放到 worker 中

          于是乎,就變成下面這個樣子:

          然后,困難如約而至,沙箱與主線程之間的鴻溝來自 dom 元素和 事件函數,這兩者無法傳遞

          我絞盡腦汁,想了一個完全之策

          將不能傳遞的東西保存到自己線程中并建立映射,將索引傳到另一個線程

          比如,事件是這樣傳遞的:

          let handlers = new WeakSet()
           if (props) {
           for (const k in props) {
           if (k[0] === 'o' && k[1] === 'n') {
           let e = props[k]
           let id = handlers.size + 1
           handlers.set({ id: e })
           props[k] = id 
           }
           }
           }

          將事件放到 map 中存起來,然后將 id 傳給主線程,主線程事件觸發的時候,將 id 和 event 參數交還給 worker

          for (const k in props) {
           if (k[0] === 'o' && k[1] === 'n') {
           let id = props[k]
           props[k] = event => {
           // 不能傳太多,此處省略對事件的簡化操作
           worker.postMessage({
           type: EVENT,
           event,
           id
           })
           }
           }
          }

          然后在 worker 中,根據索引映射,找到對應的事件并觸發

          是的沒錯就是這樣,這個方法是萬能的,比如我們的 diff 方法

          既然 diff 無法將 dom 傳出去,那么我們就傳 dom 的 index

          if (oldVNode ==null||oldVNode.type!==newVNode.type) { 
           parent.insertBefore(createNode(newVNode), node)
          }

          比如這個方法,parent 和 node 都是 dom 元素,是沒辦法傳遞的,我們就……傳他們的索引,may be 長這樣:

          [ [0,'insertBefore',1] ]
          

          dom 是這樣的:

          <div id="root" index="0">
           <ul index="1">
           <li index="2" />
           <li index="3" />
           </ul>
          </div>
          

          如果此時我們要刪除 index 為 3 的節點,那對應生成的結構,應該是這樣:

          [ [1,'removeChild',3] ]
          

          刺不刺激,我們成功找到了一個思路,能夠實現不同的 diff 算法啦

          要知道,微信小程序就沒有找到類似的思路,他們的 diff 還是 virtual-dom 的那套古老的深度遍歷,代碼多性能差……

          綜上所述,上面介紹了雙線程的主要思路,這些思路不僅僅適用于這個框架,同樣適用于其他跨端的場景

          vue 3

          這里簡單說一下 vue 3,嗯大家看到,voe 的名字和 API 神似 vue 3,事實上我確實將 vue 3 的核心抄過來了,包括依賴收集,響應式,狀態更新,組合函數……

          這只是順手的事兒,其實比起 voe 的核心思路,API 是沒什么所謂的

          因為幾乎所有的公司,如果想要搞自己的小程序,都只能過來參考思路,然后 API 很可能就和微信保持一致了

          所以我覺得 vue 3 的 API 足夠簡單,正好可以弱化 API

          就抄過來了……

          大家可以可以將 voe 作為 vue 3 的最小實現,用于協助閱讀源碼也是很 OK 的哈!

          雙線程 vs 異步渲染

          題外話,大家應該都知道我之前寫的框架 fre.js,也應該對 concurrent(時間切片)、suspense 等異步渲染的機制有所了解

          如今我又來搞 web worker,是因為它倆的思路是類似的,場景也是一樣的

          1. 時間切片是利用宏任務,將 diff 等低優先級任務后放到宏任務隊列中,從而模擬了雙線程,不阻斷 UI
          2. 雙線程是利用 web worker,將 diff 等高計算力的任務放到 worker 中,從而不阻斷主線程 UI 渲染

          兩者的場景同樣都是可視化,高幀率動畫,大量數據與計算……

          可惜本身這種場景需求實在太少了,所以 preact 和 vue 團隊紛紛發聲,表示不想搞也不需要搞::>_<::

          但是到我這來說的話,其實我不在意框架有沒有人用,也不在于業務的,我更加傾向于一種技術創新,所以從這個方面,只要是新的思路,總歸有它的價值

          總結

          呼~終于寫完了,在掘金發文,必須要長啊

          最后放上 voe 的 github:

          github.com/132yse/voe


          作者:132


          鏈接:https://juejin.im/post/5dd1edf3e51d4561ea3fb3cd


          主站蜘蛛池模板: 无码精品人妻一区二区三区影院 | 亚洲第一区精品观看| 国产伦一区二区三区高清| 男人的天堂亚洲一区二区三区| 亚洲AⅤ无码一区二区三区在线 | 国产福利91精品一区二区三区| 国产乱子伦一区二区三区| 亚洲综合一区国产精品| 风间由美性色一区二区三区| 一区二区三区中文字幕| 视频一区在线免费观看| 欧洲亚洲综合一区二区三区| 亚洲a∨无码一区二区| 日韩在线不卡免费视频一区 | 久久中文字幕无码一区二区| 亚洲国产成人久久综合一区| 无码视频一区二区三区在线观看| 一区二区三区免费高清视频| 日韩精品一区二区午夜成人版 | 亚洲国产av一区二区三区丶| 亚欧色一区W666天堂| 久久久久成人精品一区二区| 国产精品熟女一区二区| 无码一区二区三区在线观看| 日韩人妻无码一区二区三区99| 色欲综合一区二区三区| 手机福利视频一区二区| 中文字幕精品一区二区| 亚洲精品色播一区二区| 午夜视频在线观看一区| 国产一区二区在线观看麻豆| aⅴ一区二区三区无卡无码| 亚洲男人的天堂一区二区| 不卡无码人妻一区三区音频| 亚洲乱码国产一区三区| 美女毛片一区二区三区四区| 国产一区二区三区小说| 美女福利视频一区二区| 国产在线精品一区二区夜色| 久久一区不卡中文字幕| 乱码人妻一区二区三区|