112020.6

纯CSS实现Table固定表头和首列

Table固定表头和首列这种需求应该比较常见。以往的做法,需要写一大堆脚本,而现在,可以使用position:sticky轻松实现这个效果。

.table-container {
width: 100%;
height: 100%;
overflow: auto;
}

/* 首列固定 */
.table-container thead tr > th:first-child,
.table-container tbody tr > td:first-child {
position: sticky;
left: 0;
z-index: 1;
}

/* 表头固定 */
.table-container thead tr > th {
position: sticky;
top: 0;
z-index: 2;
}

/* 表头首列强制最顶层 */
.table-container thead tr > th:first-child {
z-index: 3;
}

HTML结构上,必须将 <table> 放在 <div class="table-container"> 子节点,且内部不要有其他 position 设置。

14:48:16 已有2条回复
  1. 但是在表格上面还有其他内容的时候纯css就比较难,头部的内容不能左右滚动,
    div - 宽带 屏幕100% 可以上下滚动,不能左右滚动

    表格 - 上下左右滚动, 首行吸顶,首列固定

    没找到不需要js的解决方案
    #1104 Blaze 2021-11-12 00:59 回复
  2. 肯定的,css的能力是描述性质,很难像编程一样灵活
    #1107 回复给#1104 否子戈 2021-11-15 22:28 回复
102020.6

NPM 版本范围控制

092020.6

angularjs有什么点可以碾压vue, react之流

这里所指的angularjs是只angular早期的1.x版本。虽然vue, react在热度上已经碾压angularjs几条街,但是在面对web开发(以DOM为中心的开发)中,某些场景下面,angularjs可能比任何框架或库都做得好。这里,主要举例两个点。

Modal弹窗的隐现

现在是单向数据流和immutable的天下,其目的是为了数据流所蕴含的业务流清晰,但代价是代码编写变得复杂。举一个例子,用react写一个弹出框modal,按照单向数据流的范式,必须将modal的隐现通过一个prop来控制,而这个prop必须由外部组件传入,为了控制这个prop,就必须再配合一个回调函数来触发prop的改变。这是对modal组件而言,而对于外层调用modal组件而言,必须自建一个state传给对应的prop,同时,必须自建一个方法作为回调函数传给modal。这里面编程出错的几率远远大于保证业务流正确的几率,也就是成本的提升。因为,你必须在回调函数中,正确处理state的变化值。

而双向数据绑定则完全不需要,传入prop之后,不需要再在回调函数中修改state,双向绑定逻辑会自动修改state。(当然,这基于不同的数据思想,一个是immutable,一个是mutable,各自不同。)虽然基于的范式不同,但是一个modal的显示和隐藏在双向数据绑定范式下,更有利。

表格固定列

Web表格(grid table)是前端交互领域及其复杂的一个场景。其中的一个需求是,固定表格的前n列,剩下的可以左右滑动来查看。在基于 virtual dom 的 vue, react 编程中,自己手写是及其麻烦的,你需要手动在模板中拆分块,在脚本中拆分数据。总之,由于virtual dom的编程范式如此,本身就是要隔绝dom的操作。但是实际上,在前端领域,grid table的操作往往是virtual dom最早提出来的,基于数据变化,只修改小部分dom的需求。但是,实际上最终,virtual dom类编程,在这个点上,反而是最辣鸡的。辣鸡之点不在于性能,而在于编程的复杂。

而使用angularjs则太过便利。首先,angularjs也是基于数据响应更新界面的。其次,angularjs是基于DOM操作进行渲染的。所以,在angularjs中,如果要实现表格固定列的需求,只需要写一个directive,使用 template() 函数来动态返回模板,返回的模板是字符串,于是可以各种骚操作修改字符串来控制html结构,这比vue、react的结构编程快上10倍不止。接下来是对DOM的重新调整,当按照模板结构和样式完成渲染之后,你可能还需要调整列宽度、位置、滚动条是否显示、左右两边每行的点击联动、左右都可滚动(pointer-events: none;)等等操作,在不修改任何数据的情况下,瞬间通过DOM操作完成。而如果这些东西依赖virtual dom去做,可以说极其麻烦,代码量上翻10倍很正常。

除了上述这两个例子外,我在开发中还会碰到其他的一些场景,发现有的时候恨angular是垃圾,有的时候又觉得它diao。总之,在不同的场景下,不同的编程范式所带来的收益是不同的,但是问题点在于,我们无法真正的完全在同一套代码中享受不同范式的好处。这也是前端框架的一个不足之处吧。

13:26:17 已有0条回复
282020.5

react-tyshemo-form 发布

昨晚想到了很晚,睡不着,然后就实现了它,今天就把它发布了。react-tyshemo-form基于tyshemo的model实现响应式,基于react-tyshemo实现react和model的绑定,最终体现为一个Field组件。

<Field model={model} name="field" component={FieldComponent} />

整个包的核心就在这个Field组件上面,它基于我早前在robust中提出的表单范式理论,对于表单视图而言,实际上只需要 value, required, disabled, readonly, hidden, errors 这几个信息,以及一个 onChange 回调函数。所以,这这个 Field 组件的实现上,完全遵照这个理论去做,对于用于展示字段 UI 的组件,只需要接收这些 prop 就够了。当然,为了必要的扩展,Field 也支持一个 extend 属性,用来确保可以传入其他 prop。

以上面这段示例代码为例,<Field /> 只是一个驱动器,主要作用是确保 model 上的 field 字段值发生变化时,可以重新渲染该字段。仅此而言,所以使用也超级简单。

14:04:52 已有0条回复
272020.5

领域模型 Domain Model

今天学到的新知识点,领域模型 Domain Model。简单总结一下,什么是领域模型?领域模型有哪些好处?如何在开发中运用领域模型?

什么是领域模型?

有两个领域对领域模型做出解释。

  • 管理领域:领域模型是对整个行业的工作模式的抽象总结。
  • 软件领域:领域模型是对对象普遍性的最高抽象。

虽然出发点不同,但是实际上表达意思的核心思想是一致的。要理解领域模型,首先看下“领域”的概念。横向比较,domain对应的是range,domain是定义域,range是值域。纵向对比,领域是比专业/职业/业务更高水平的概念,例如我们经常说“机器人领域”“水产品领域”“航空航天领域”。“领域模型”概念的核心思想,就是寻找某一宽泛范围内的行为模式的共性,抽象为可适用于这一范围内所有行为的普遍性原则、规律或方法。

在编程领域怎么去理解?从大的层面讲,电商类应用与OA办公应用是两个领域的应用,它们适用不同的业务领域模型。从小的角度讲,用户鉴权和订单跟踪这两个业务完全不同,适用不同的编程领域模型。这里你可以发现两个点:1)虽然鉴权和订单领域模型不同,但是这两个业务之间可能存在联系,比如是否得到订单信息基于鉴权的结果;2)虽然电商应用和OA应用业务场景不同,但是它们可能都需要鉴权。

所以,从编程角度看,领域模型实际上既要解决对象抽象的问题,也要解决对象间的关系问题,还要解决在什么事件下触发对象关系的转变问题。

领域模型有哪些好处?

这里的好处是指相对于业务模型来说。我们开发过程中,经常基于业务场景去进行设计。而一个应用系统的开发,必须应对业务需求的变化。特别是办公软件这种系统,一个企业使用办公软件,必然遵循企业管理的流程,而流程变更是常有的事,基于业务场景去设计和架构软件,并持续迭代,最终带来的后果就是在多次迭代之后,不得不进行重构。而如果该次重构仍然基于业务模型去重构的话,必然还会经历再一次的重构。因为一个业务模型是无法适应所有业务场景的。所以,一旦现实中的业务需求迭代了,给原有的技术架构造成必须重构的影响时,开发者没有任何回旋余地。

而如果基于领域模型设计软件,那么可能接受的代价更小。在分析业务本身时,不只为了实现业务去设计架构,而是从行业的普遍性出发去设计架构,同时结合自己的业务特征,再在设计好的架构上包上一层。哪一天自身的业务发生变化,往往只需要在上面包的那一层上做调整。在软件整体上,分不同的层“视图层-业务层-数据层”,在每一层中又具体的去划分,比如业务层“领域模型-业务模型-流转模型”。而且在设计之初,每一个领域(鉴权、订单等)都采用行业标准,再在行业标准基础上包一层实现定制。那么这一就可以以最小的成本,把知识沉淀在自己的真实业务代码中。

如何运用领域模型?

以下是我在这篇文章中看到的建议。

  • 理解后端领域模型
  • 建立前端领域模型
  • 分离领域层
  • 主导接口约定
  • 开发中注意业务含义
  • 实时同步

简单讲,就是要建立抽象类,这些类去定义领域对象的属性、方法,而且这些类要有一定的内在联系,可扩展。在视图层可以被很好的使用,并不需要在视图层去撰写业务逻辑。

一些相关话题的文章:

  • https://juejin.im/post/5d3926176fb9a07ef161c719
  • https://zhuanlan.zhihu.com/p/37904835
  • https://juejin.im/post/5b1c71ad6fb9a01e5918398d
  • https://zhuanlan.zhihu.com/p/109114670
  • https://www.jianshu.com/p/fe45506ea358
  • https://zhuanlan.zhihu.com/p/59886663
  • https://www.cnblogs.com/luminji/p/3703082.html

另外,刚才在阅读的时候,发现“视图模型”“业务模型”“领域模型”这些概念。现在前端编程实际上大部分是杂糅“视图模型”和“业务模型”,也就是MVVM中的VM那一套东西,真正的MVC还非常少见。

22:08:17 已有0条回复
202020.5

现代 Web 开发的现状与未来(JSDC 2019 演讲全文)

192020.5

vue.js 纪录片

162020.5

var === undefined vs. typeof var === 'undefined'

全等号 === 已经在我日常开发中占据绝对位置,在我开发中所有判断里面,== 已经被当作奇淫巧技了,不在万不得已的情况下,不会使用,其地位和分号; 等同。所以,现在讨论如何判断一个值是否为 undefined 的时候,我只会用 ===。

现在的问题是,在 var === undefined vs. typeof var === 'undefined' 这两种判断中,谁更好?先说结论,使用 typeof 的方法更好。最主要的原因有两点:

  • var === undefined 的形式,你不能确保 var 被声明过,当 var 没声明过时,程序直接报错,而使用 typeof 可以用来判定一个变量是否声明过,这也是我们常用的 typeof window ... typeof global ... typeof self ... this 这个办法来搞定不同运行时环境下的处理。
  • undefined 竟然是 window 的属性,按理来说作为 js 语言的基础类型,提供和 null 一样的关键字应该由语言解释器来做吧,但是在运行时中(浏览器),undefined 和 null 完全是两个层面的东西,null 是内置于解析器的空指针符号,而 undefined 是挂在 window 上的全局变量,竟然是挂在 window 上的变量,那么每次使用 var === undefined 时,实际上会去 window 上读取变量,读取的多了,也就让我们开始遐想有没有办法通过不断调用 undefined 变量使系统崩溃。不过值得庆幸的是,undefined 是不能重新赋值的,undefined = 1 虽然不会报错,但是没效果。而执行 null = 1 则会直接报错。就是这么奇妙。

虽然使用 typeof 要多写好多个字母,但是,抛开其他各种个人偏好问题,上面这两个理由足以让人选择 typeof 的形式来判断 undefined 了。

00:12:48 已有0条回复
012020.5

刚开始注册了codepen,用了一会儿就开始不舒服,咋只能用cdn连入包呢?然后转战codesandbox,这才是我要的呀。直接在线写项目,毫无压力,包管理,在线编译查看效果,一切都非常符合我的口味。顺带,看了 codesandbox 的实现原理,浏览器端实现编译,也是牛皮哄哄的。当然,说了这么多,我主要还是用它来实现 demo 效果,感觉也是嘴上说的好,实际上也是牛刀杀鸡用。

17:29:57 已有0条回复
302020.4

React 状态管理的另一个世界,mutable state 状态管理器 react-tyshemo 发布

在 react 状态管理领域,react-redux 可谓是只手遮天了,基于 flux 思想实现,小巧,immutable 的思想让数据变化可控。但 immutable 所带来的编程代价太大了,如果你要更新一个深层结构的对象的某个节点,写作将会是极其麻烦的一件事,而且还保不准会出错。为了保证 immutable,redux 的 reducer 机制让开发者掉光了头发。于是有了类似 dva、rematch 等这样的项目,这些项目基于 redux 再做了一层封装,让开发者少写了很多 reducer 相关的代码,但是很无奈,immutable 的特性,让开发需要付出更多的精力来控制每一个更新。

再另一个世界,mutable state 其实也非常优秀。知名的 mobx 推出了 mobx-react 和 react-redux 竞争。然而,原本非常优秀的 mobx 却只管把自己的想法强加于人,而忽视了代码写作的便捷性,总之,使用起来虽然不用再为 reducer 头疼,却对组件的侵入和让人很不适应。你需要了解它的概念,特别是基于观察者模式的很多概念,它提供的 api 的形式也很丰富,基于接口的、装饰器的,总之,你在掀开它的魔法盒子时,会忍不住“wo\cao/”,但当你真正在项目中尝试使用它时,确会不由但发出“wo^cao\”,但就在心智折腾上,就让人抓狂,还不知道会产生多少副作用 bug。

在 mutable 数据管理最优秀的,莫过于 vue。无论初识还是长久,都会与 vue 的响应式数据相看两不厌。它简介的用法,以及把基本原理告诉你,让你尽情去修改数据。Mutable 相对于 immutable 的最大好处,就是可以对对象任意节点上的对象进行修改,而无需仔细的把握这个节点在整个 state 的什么位置上,在 redux 的实践中,你可能都已经厌烦了写 ... 来解构对象/数组了,但在 vue 中,根本不需要担心这一个点,直接逮住一个对象,立即修改它的某个属性,完事走人,不需要先构造出一个新的数据,不需要调用某个接口把这个新数据传入进去。虽然 redux 那种每一个状态都是全新的思想很好,但是,你的状态不可能是全新的,每一个被认为是全新的状态,都包含了老状态的一部分(对象节点),而这些引用,可能带来后续的错误。在 react 生态中,你可以使用 immutable.js 来尽可能避免这个问题。

但是在 vue 生态中,用于管理全局状态的 vuex 确非得要引入 mutions, actions 的概念,这都是从 flux 借鉴过来的,而且很奇怪的是,在 mutions 中定义的修改,又要到 actions 中重做一遍。实在是有点自废武功啊。有没有一种方法,可以在 react 中真正享受 vue 式的数据管理?你不妨来试试下面的代码:

function MyComponent(props) {
  const { one } = props
  const { name, age, height, married, sex, changeSex, me, book, updateBook } = one
  return (
    <>
      {!!me && (
        <>
          <span>{me.user_name_zh}, {me.user_position}</span>
          <br />
        </>
      )}
      <span>{name}: {age}, {height}, {married ? 'married,' : ''} {sex ? 'F' : 'M'}</span>
      <br />
      <span>book: {book.price || 0}</span>
      <br />
      <button type="button" onClick={() => one.age ++}>grow</button>
      <button type="button" onClick={() => changeSex(!sex)}>change</button>
      <button type="button" onClick={() => updateBook({ price: (Math.random() * 100).toFixed(2) })}>update</button>
    </>
  )
}

const mapToProps = (contexts) => {
  const { one } = contexts
  return {
    one,
  }
}

export default connect(mapToProps)(MyComponent)

看这代码啊,和 react-redux 有点像,完全可以理解是不。

在数据开始对组件进行注入的时候,保持和 react-redux 一致的使用效果,这实在是无缝的思想过渡,你觉得从原来写 react-redux 的代码到写这样的代码,会有压力吗?没有,一点都没有。下面来看看这种全局状态管理的真面目:

import React from 'react'
import { use, connect } from 'react-tyshemo'

class Book {}

use({
  name: 'one',
  state: {
    name: 'one',
    age: 10,
    book: new Book(),
  },
  computed: {
    height() {
      return this.age * 5
    },
  },
  watch: {
    age({ value }) {
      if (value > 22) {
        this.married = true
      }
    },
  },
  methods: {
    changeSex(sex) {
      this.sex = sex
    },
    updateBook(data) {
      Object.assign(this.book, data)
      this.dispatch('book')
    },
  },
  hooks: {
    onUse() {
      fetch('/api/me').then(res => res.json()).then((json) => {
        const { data } = json
        this.me = data
      })
    },
  },
})

看完什么感受?“wo/cao/” 绝对是抄 vue!连属性名字都和 vue 组件一毛一样(多了一个 hooks)。用一个 use 函数注册一个 state 的 namespace,并且这这个注册定义对象中,传入 state, computed, methods, watch 等来实现状态数据的处理。由于对数据的操作和 vue 是一摸一样,所以,你不用担心 ajax 请求的异步问题了,不需要考虑一大堆 redux 带来的“解决问题带来的问题”。而且,react-tyshemo 只提供几个函数接口,避免 mobx-react 那般复杂。

看上去是不是很舒服呢?

马上体验

22:48:09 已有0条回复