使用CSS连接数据库的方式


Posted in HTML / CSS onFebruary 28, 2022

 使用CSS连接数据库的方式

故事背景

某公司招聘需求如下:

我们正在寻求可以 使用CSS连接数据库 的前端伙伴~

使用CSS连接数据库的方式

自从我上次开始一个高质量的“发帖”以来,已经有很长一段时间了,事实上,它已经很长一段时间了,那时候我的词汇表中可能还没有“水帖”这个词。

为此,我受到了一个早期项目的启发,该项目基于区块链初创公司将投资者的脸投影到3D立方体上让我想起了以前的互联网,那时一切都很奇怪。

好汉不提当年勇。所以今天,我将讨论如何管理我自己的新项目: sqlcss.xyz [1]

使用CSS连接数据库的方式

顾名思义,这就是使用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连接数据库的方式

我遗漏了一件事,就是所有这些查询结果特别多的时候,如何更好的渲染展示的问题。如果查询结果有很多,他们需要分开到单独的行。这与本文的主题-- 使用CSS连接到数据库 并没有太大关系,所以我认为在这里谈论这个问题并不合适,但如果你想进一步了解这个"荒谬"的概念, git上的代码都是可用的 [8] 。

译者补充

  • SQLite是由C语言编写的嵌入式轻量级数据库,广泛用于IOS和Android的App中。若有读者想要在浏览器端应用SQLite,推荐使用SQLite的WebAssembly版--sql.js,基本与SQLite的使用没有太多区别。在实际项目使用中,还需特别注意SQLite的 安全性 问题。
  • 为方便展示,特此截取本文作者所实现的CSS连接SQLite的部分demo如下:

使用CSS连接数据库的方式

使用CSS连接数据库的方式

关于文中所提到的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连接数据库内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

 
HTML / CSS 相关文章推荐
css3圆角样式分享自定义按钮样式
Dec 27 HTML / CSS
纯CSS3实现给头像加个光芒四射且旋转的背景动画效果
May 07 HTML / CSS
一款纯css3实现的动画加载导航
Oct 08 HTML / CSS
css3的transition属性详解
Dec 15 HTML / CSS
CSS3实现闪烁动画效果的方法
Feb 09 HTML / CSS
html5 Canvas画图教程(2)—画直线与设置线条的样式如颜色/端点/交汇点
Jan 09 HTML / CSS
html5 Web SQL Database 之事务处理函数transaction与executeSQL解析
Nov 07 HTML / CSS
HTML5如何为形状图上颜色怎么绘制具有颜色和透明度的矩形
Jun 23 HTML / CSS
HTML5通过调用canvas对象的getContext()方法来获取绘图环境
Jun 23 HTML / CSS
微信浏览器取消缓存的方法
Mar 28 HTML / CSS
HTML5无刷新改变当前url的代码
Mar 15 HTML / CSS
解决HTML5中的audio在手机端和微信端的不能自动播放问题
Nov 04 HTML / CSS
css常用字体属性与背景属性介绍
分享CSS盒子模型隐藏的几种方式
Feb 28 #HTML / CSS
CSS中实现动画效果-附案例
css filter和getUserMedia的联合使用
Feb 24 #HTML / CSS
css3中2D转换之有趣的transform形变效果
css3带你实现3D转换效果
bootstrapv4轮播图去除两侧阴影及线框的方法
You might like
解析用PHP实现var_export的详细介绍
2013/06/20 PHP
PHP+Mysql+Ajax+JS实现省市区三级联动
2014/05/23 PHP
用 Composer构建自己的 PHP 框架之基础准备
2014/10/30 PHP
php读取flash文件高宽帧数背景颜色的方法
2015/01/06 PHP
PHP结合jQuery插件ajaxFileUpload实现异步上传文件实例
2020/08/17 PHP
Laravel框架中Blade模板的用法示例
2017/08/30 PHP
PHP使用file_get_contents发送http请求功能简单示例
2018/04/29 PHP
PHP常用字符串函数用法实例总结
2020/06/04 PHP
js 调用父窗口的具体实现代码
2013/07/15 Javascript
jquery中animate动画积累的解决方法
2013/10/05 Javascript
JavaScript实现简单的数字倒计时
2015/05/15 Javascript
jQuery筛选数组之grep、each、inArray、map的用法及遍历json对象
2016/06/20 Javascript
js实现拖拽功能
2017/03/01 Javascript
vuejs2.0子组件改变父组件的数据实例
2017/05/10 Javascript
D3.js进阶系列之CSV表格文件的读取详解
2017/06/06 Javascript
JavaScript实现移动端页面按手机屏幕分辨率自动缩放的最强代码
2017/08/18 Javascript
React+react-dropzone+node.js实现图片上传的示例代码
2017/08/23 Javascript
Vue v2.4中新增的$attrs及$listeners属性使用教程
2018/01/08 Javascript
JS实现匀速与减速缓慢运动的动画效果封装示例
2018/08/27 Javascript
[06:36]吞吞映像top1
2014/06/20 DOTA
python导入时小括号大作用
2017/01/10 Python
Python 实现简单的shell sed替换功能(实例讲解)
2017/09/29 Python
python3实现SMTP发送邮件详细教程
2018/06/19 Python
记一次python 内存泄漏问题及解决过程
2018/11/29 Python
Pytorch根据layers的name冻结训练方式
2020/01/06 Python
如何用Python 实现全连接神经网络(Multi-layer Perceptron)
2020/10/15 Python
JOSEPH官网:英国奢侈时尚品牌
2018/01/31 全球购物
什么是命名空间(NameSpace)
2015/11/24 面试题
2014年自我评价
2014/01/04 职场文书
公务员培训自我鉴定
2014/02/01 职场文书
房地产资料员岗位职责
2014/07/02 职场文书
大学竞选班干部演讲稿
2014/08/21 职场文书
大学生党员个人对照检查材料范文
2014/09/25 职场文书
OpenCV-Python实现怀旧滤镜与连环画滤镜
2021/06/09 Python
Mysql 如何合理地统计一个数据库里的所有表的数据量
2022/04/18 MySQL
Python软件包安装的三种常见方法
2022/07/07 Python