使用CSS連接數據庫的方式

故事背景
某公司招聘需求如下:
我們正在尋求可以 使用CSS連接數據庫 的前端伙伴~
自從我上次開始一個高質量的“發帖”以來,已經有很長一段時間了,事實上,它已經很長一段時間了,那時候我的詞匯表中可能還沒有“水帖”這個詞。
為此,我受到了一個早期項目的啟發,該項目基于區塊鏈初創公司將投資者的臉投影到3D立方體上讓我想起了以前的互聯網,那時一切都很奇怪。
好漢不提當年勇。所以今天,我將討論如何管理我自己的新項目: sqlcss.xyz [1]
顧名思義,這就是使用CSS連接數據庫的方式。不幸的是,它 只能在Chrome中工作 ,但你可以提供任何你喜歡的SQLite數據庫,并通過CSS查詢它。
它是如何工作的?
首先我們需要用到一組被親切地稱為 Houdini [2] 的api,它讓你的瀏覽器能夠通過Javascript對象模型來控制CSS。換言之,這意味著您可以定制CSS樣式、添加定制屬性,等等。
可能這個作品最大的特性是 CSS Paint Worklet [3] ,它允許你在一個元素上“繪制”,就像你知道和喜歡的畫布一樣,并讓瀏覽器把它當作CSS中的圖像。這里有一些例子可以用來 演示Houdini [4] 。
然而,這個工作集只提供了Worker API的一個子集,而且畫布上下文本身也被大量剝離。這樣做的實際結果是,您的自定義CSS繪制代碼提供了一個比您預期的更小的沙盒。
這意味著什么? 沒有網絡訪問權限,因此可以和fetch和XmlHttpRequest說再見了。在繪制上下文上沒有drawText功能。其他各種JS api也消失了,以防你希望解決這些問題。
不過,不用擔心。并非一切都完了。讓我們把它分解成幾個步驟。
1. 設置數據庫
這必須是第一步,以便理解概念證明是否可行。
首先我們會借助于 sql.js [5] 。它實際上是一個通過emscripten編譯成WebAssembly和老式ASM.js的SQLite版本。不幸的是,我們不能使用WASM版本,因為它必須通過網絡獲取二進制文件。ASM版本沒有這個限制,因為所有的代碼都可以在一個模塊中使用。
雖然PaintWorklet限制了worker內部的網絡訪問,但你仍然可以導入代碼,只要它是一個ES6模塊。這意味著文件中必須有一個導出語句。不幸的是,sql.js沒有ES6的版本,所以我自己修改了sql.js,使其能夠順利的被import進入項目。
現在到了關鍵時刻:我可以在我的工作包中建立一個數據庫嗎?
const SQL = await initSqlJs({ locateFile: file => `./${file}`, }); const DB = new SQL.Database();
**成功了!**但沒有任何數據,所以我們來解決這個問題。
2. 查詢數據庫
一開始最簡單的方法就是設置一些假數據,sql.js有兩個函數可以做到這一點。
DB.run('CREATE TABLE test (name TEXT NOT NULL)') DB.run( 'INSERT INTO test VALUES (?), (?), (?), (?)', ['A', 'B', 'C', 'D'] )
我有了測試表,里面有一些值。我應該能夠查詢這個并獲得這些值,盡管我不確定得到什么樣的結構化查詢結果。
const result = DB.exec('SELECT * FROM test') console.log(result)
正如預期的那樣,結果已經出來了。不過,渲染展示通過CSS查詢數據庫的結果會更好。
3. 渲染結果,最簡單的方法
我認為這就像在畫布上寫文本一樣。這有多難,對吧?
class SqlDB { async paint(ctx, geom, properties) { const result = DB.exec('SELECT * FROM test'); ctx.font = '32px monospace'; ctx.drawText(JSON.stringify(result), 0, 0, geom.width); } }
不,那樣就太簡單了。這里的上下文與畫布元素的上下文不同,它只提供了功能的一個子集。
當然,它仍然可以繪制路徑和曲線,所以缺乏方便的API是一個障礙,但這一切都不是問題。
4. 不使用文本API創建文本
幸運的是,我們可以借助于 opentype.js [6] 所提供的解決方案。它可以解析一個字體文件,然后,給定一個文本字符串,生成每個字符的字母形式。這個操作的實際結果是一個表示字符串的路徑對象,然后可以將其呈現到上下文中。
這次我不必修改opentype庫來導入它,因為它已經可以從 JSPM [7] 中獲得。所以,如果你給JSPM一個npm包,它會自動生成一個ES6模塊,你可以直接導入到你的瀏覽器中。這是非常棒的,因為我真的不想為了一個有趣的項目而使用打包工具。
import opentype from 'https://ga.jspm.io/npm:opentype.js@1.3.4/dist/opentype.module.js' opentype.load('fonts/firasans.otf')
但這里有一個問題——它想通過網絡加載字體,而我不能這樣做!嗨,挫敗了!
……而且?它還有一個接受數組緩沖區的解析方法。我將用base64編碼字體,然后在我的模塊中解碼它。
import opentype from 'https://ga.jspm.io/npm:opentype.js@1.3.4/dist/opentype.module.js' import base64 from 'https://ga.jspm.io/npm:base64-js@1.5.1/index.js' const font = 'T1RUTwAKAIAAAwA ... 3 days later ... wAYABkAGgAbABwAIAKM' export default opentype.parse(base64.toByteArray(font).buffer)
我告訴過你worklet也沒有處理base64字符串的api嗎?atob和btoa都沒有!我也不得不為此找到一個普通的JS實現。
我把這段代碼放在它自己的文件中,因為它不太符合人體工程學……必須在剩下的代碼旁邊使用大約200kb的編碼字體字符串。
這就是我為何要濫用ES模塊來加載我的字體的原因。
5. 渲染結果,另一種簡單的方式
從現在起,所有繁重的工作都由opentype庫來完成,所以我所需要做的就是用一點數學知識來對齊。
import font from './font.js' const SQL = await initSqlJs({ locateFile: file => `./${file}`, }); const DB = new SQL.Database(); DB.run('CREATE TABLE test (name TEXT NOT NULL)') DB.run( 'INSERT INTO test VALUES (?), (?), (?), (?)', ['A', 'B', 'C', 'D'] ) class SqlDB { async paint(ctx, geom, properties) { const query = DB.exec('SELECT * FROM test') const result = query[0].values.join(', ') const size = 48 const width = font.getAdvanceWidth(queryResults, size) const point = { x: (geom.width / 2) - (width / 2), y: geom.height / 2 } const path = font.getPath(result, point.x, point.y, size) path.draw(ctx) } } registerPaint('sql-db', SqlDb)
最好再來一些HTML和CSS看看發生了什么。
<html> <head> <script> CSS.paintWorklet.addModule('./cssdb.js') </script> <style> main { width: 100vw; height: 100vh; background: paint(sql-db); } </style> </head> <body> <main></main> </body> </html>
成功了!但這里沒有足夠的CSS,而且查詢是硬編碼的。
6. 通過CSS查詢
如果必須使用CSS來查詢數據庫,那就更好了。事實上,這是我們可以在Paint Worker的上下文之外與其通信的唯一方式,因為沒有與Web worker一樣的消息傳遞API。
為此,需要一個定制的CSS屬性。定義inputProperties的好處是可以訂閱該屬性的更改,因此如果該屬性的值發生更改,它將重新呈現。不需要設置任何訂閱者自己。
class SqlDb { static get inputProperties() { return [ '--sql-query', ] } async paint(ctx, geom, properties) { // ... const query = DB.exec(String(properties.get('--sql-query'))) }
這些CSS屬性被稱為類型化屬性,但它們本質上被封裝在一個特殊的CSSProperty類中,而這個類本身并不是很有用。因此,你必須手動將其轉換為字符串或數字或其他類似的使用它,如上所述。
現在對CSS做一個快速調整。
main { // ... --sql-query: SELECT name FROM test; }
引號在這里被故意省略了,因為否則在將字符串傳遞給數據庫之前,我必須將它們從字符串中刪除。也就是說,這很有效!
任務完成!
如果你玩過sqlcss。你會注意到我并沒有滿足于此。在進行了一些重構之后,又進行了一些更改。
7. 導入數據庫文件
硬編碼數據庫模式和實際數據,有點糟糕。它證明了這個概念,但我們肯定可以做得更好。
如果您可以查詢任何您喜歡的數據庫,只要您手邊有數據庫文件,那就太棒了。我只需要讀取這個文件并對其進行base64編碼,就像我對字體文件所做的那樣。
const fileInput = document.getElementById('db-file') fileInput.onchange = () => { const reader = new FileReader() reader.readAsDataURL(fileInput.files[0]) reader.onload = () => { document.documentElement.style.setProperty( '--sql-database', `url('${reader.result}')` ) } }
我為此做了一個額外的CSS屬性,在這個屬性中,您可以將SQLite數據庫作為base64編碼的數據URI提供。data URI只是為了顯示并確保它對DOM是有效的,我將在Worker層面解析這些東西。
最后一步是使其更易于查詢,因為否則您必須進入調試器來操作元素的CSS。
8. 編寫查詢語句
這可能是項目中最簡單的部分。自定義屬性對于分號有一點問題,而SQLite并不關心末尾的分號是否被省略,所以最簡單的做法是,如果在輸入中找到它,就刪除它。
const queryInput = document.getElementById('db-query') queryInput.onchange = () => { let query = queryInput.value; if (query.endsWith(';')) { query = query.slice(0, -1) } document.documentElement.style.setProperty( '--sql-query', queryInput.value ) }
從現在開始,您可以使用CSS導入和瀏覽您自己的數據庫了!
我遺漏了一件事,就是所有這些查詢結果特別多的時候,如何更好的渲染展示的問題。如果查詢結果有很多,他們需要分開到單獨的行。這與本文的主題-- 使用CSS連接到數據庫 并沒有太大關系,所以我認為在這里談論這個問題并不合適,但如果你想進一步了解這個"荒謬"的概念, git上的代碼都是可用的 [8] 。
譯者補充
- SQLite是由C語言編寫的嵌入式輕量級數據庫,廣泛用于IOS和Android的App中。若有讀者想要在瀏覽器端應用SQLite,推薦使用SQLite的WebAssembly版--sql.js,基本與SQLite的使用沒有太多區別。在實際項目使用中,還需特別注意SQLite的 安全性 問題。
- 為方便展示,特此截取本文作者所實現的CSS連接SQLite的部分demo如下:
關于文中所提到的jspm,這里引用其官網的介紹如下:jspm為導入映射提供了模塊CDN和包管理,允許任何來自NPM的包都可以直接在瀏覽器中加載,無需進一步的處理。
參考資料
[1]
sqlcss.xyz: https://www.sqlcss.xyz
[2]
CSS Houdini: https://developer.mozilla.org/en-US/docs/Web/Guide/Houdini
[3]
CSS Paint Worklet: https://developer.mozilla.org/en-US/docs/Web/API/PaintWorklet
[4]
houdini how: https://houdini.how/
[5]
sql.js: https://sql.js.org/#/
[6]
opentype.js: https://opentype.js.org/
[7]
jspm: https://jspm.org/
[8]
sqlcss git: https://git.sr.ht/~mrlee/sqlcss
到此這篇關于使用CSS連接數據庫的方式的文章就介紹到這了,更多相關CSS連接數據庫內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章,希望大家以后多多支持腳本之家!
相關文章
- 這篇文章主要介紹了使用CSS連接數據庫,顧名思義就是使用CSS連接數據庫的方式,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考2022-02-25
- 這篇文章主要介紹了 css常用字體屬性與背景屬性,css可以做出很多使html樣式的改變,今天主要說一說字體樣式與背景樣式,字體樣式的分類根據名字就可以判斷出來,下面文章的2022-02-25
- 這篇文章主要分享的是CSS盒子模型隱藏的幾種方式,盒子的隱藏會使做出來的界面更加精致,靈活,帶給用戶更好的使用體驗,盒子的隱藏使用css與js會有更好的動畫效果,下面我i2022-02-25
- 這篇文章主要為大家介紹了企業開發CSS命名BEM代碼規范的實踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-02-08
- 本文只展示自適應布局的方案。不展示手動指定寬度的那種方案,通過實例代碼給大家介紹的非常詳細,對CSS實現九宮格布局(自適應)的示例教程感興趣的朋友一起看看吧2022-01-24
- 這篇文章介紹了使用CSS設置滾動條樣式,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-12-20
- 這篇文章主要介紹了在CSS中使用when/else的方法,關于使用 @if 還是 @when 的問題也存在一些爭議,怕 @if會與 Sass 沖突,還有一個建議是用 @where 來代替,具體內容詳情跟2021-12-15
- 需要實現一個邊框長度比容器長度小一些的邊框時,以往大多數都是使用div嵌套?,F在只需要使用偽類就可以實現這個效果,并且使用起來很方便,下面通過本文給大家介紹CSS使用2021-12-15
- 本文基于一些高頻出現在設計稿中的,使用 CSS 實現稍微有點難度和技巧性的按鈕,講解使用 CSS 如何盡可能的實現它們,讓我們一起看看使用 CSS 輕松實現一些高頻出現的奇形2021-12-01
- CSS 中的2D轉換允許我們在二維空間中執行一些基本的變換操作,例如移動、旋轉、縮放或扭曲等,本文主要介紹了CSS常用的五個變換:translate()、rotate()、scale()、skew()2021-11-30
最新評論