電子佛典 app 新支援樹狀目錄


上個禮拜六、日,我又想到我這款電子佛典 app – cbetar2 可以加什麼新功能。我這款 app 起初是為手機、平板的觸控裝置設計,因此它的 UI 較適合觸控,其中佛經目錄的瀏覽是一頁一層目錄列表呈現,這種好處是每列可以足夠大,方便手指觸控。但操作時想從目前一層往上跳 n 層,就得按 n 次向上鈕,不過這也是不得已的妥協。

然而我這款 app 另一設計訴求就是跨平台,不止觸控裝置可以用,桌機、各種作業系統都可以用。因此此種觸控 UI 在桌機上運作就不是這麼適合,雖然堪用,例如過大的 UI 讓滑鼠的滑動距離變有些長。

後來參照一些桌機用的電子佛典 app,發現它們都使用樹狀目錄,較適合滑鼠操作,這使得我想改造我的 app 支援可切換觸控與鍵鼠 UI。要做樹狀的佛經目錄 UI,首先要有樹狀結構的佛經目錄資料、樹狀 UI 元件,還有將資料轉為 UI 的演算法。CBETA 經文檔有提供樹狀佛經目錄資料,格式是 XML,把它讀入記憶體後,可以作一些處理,產生新的樹狀資料,例如把分開的樹狀目錄資料合併成單一樹狀資料。

“遞迴”是一個操作樹狀結構很好用的演算法,很適合做上述樹狀資料的處理與樹狀 UI 的生成。要了解遞迴如何處理一棵樹,首先可以將樹表示為節點與分枝的組成。一棵樹由根節點開始作分枝,長出子節點。這些子節點又能再分枝長出它們的子節點。而遞迴處理的切入點就是每個節點都做類似的事,以程式來講可以表示為一個 function:每個節點除了作自己負責的事,也可以呼叫它的子節點作事。而這些子節點也是作類似的事,也就是用同一個 function 作事。如此一來只要從樹的根節點啟動 function call,就能讓每個節點都作事。這種 function 呼叫自己的演算法就是遞迴。遞迴還有一重要注意事項,就是在最終端的”葉節點”,要終止遞迴下去,忘了寫這條件可是會造成無窮遞迴。以下為一段遞迴 function 的範例:

function recursive(node: Node) {
    // Recursion stop.
    if (node.childNodes.length === 0 {
        return;
    }

    // Recursive to child nodes.
    return node.childNodes.forEach(cn => {
       return recursive(cn);
    });
}

有了樹狀資料,接著仍是使用遞迴將它們對應成樹狀 UI 元件即可。但我遇到一個小挑戰,就是我這支 app 是基於 react + Ionic Framework 寫 UI,但 Ionic 是一款觸控裝置用的 UI,因此缺少鍵鼠常用的 Tree UI 元件。幸好搜尋發現有另一款知名的 react UI framework – Material UI,它就有 TreeView 可以用。所以,這可是我第一次嘗試混用不同 UI frameworks,感覺滿有挑戰、有趣。混用的過程也的確遇到一些問題,例如我想用 Material UI drawer 元件,但會被 Ionic 元件遮住,只好改用 Ionic drawer。看來混用不同的 frameworks 不止要學兩邊的 coding styles,還要考量彼此相容性的問題。最後完成的 codes 可以在 GitHub 找到:https://github.com/MrMYHuang/cbetar2/blob/master/src/components/CatalogDesktop.tsx

結論:寫程式遇到樹,用遞迴就對了。混用 frameworks,可以各取所需,但也要兩邊都學、彼此可能衝突。


Leave a Reply