Results 199 issues of 行列

### HTML规范 对于一个布尔属性,如果节点存该属性`key`,则表示为`true`,否则为`false`,当存在属性时`key`时,无视`value`是什么值。如下`input`的`checked`属性 ```html ``` 我们会发现节点的布尔属性只要存在即为`true`,尽管它的`value`是`javascript`中的`falsy`值。这是因为`html`与`javascript`是两回事,不能拿`javascript`中的`falsy`值在`html`中使用。 ### HTML的扩展 诚然,对于`html`来讲,有它自己的规范考量。我们在使用时,多少会有些不方便,比如用`innerHTML`渲染一段`html`片断时,我们只能根据条件来输出是否有`checked`这样的布尔属性来表达相应的界面,比如 ```ts body.innerHTML=`` ``` 这多少有点不方便,如果`html`中的属性本身就支持根据`trusy`或`falsy`的值来表达相应的界面该多好? #### 虚拟DOM的扩展 以`react`为代表的使用虚拟`dom`的框架如何处理该问题? ```tsx ``` 此为扩展了`html`属性`value`的处理,当属性值为`falsy`时,删除相应的属性 #### 片断解析 以`fast`为代表的解析引擎则扩展了属性`key`,https://www.fast.design/docs/fast-element/declaring-templates ```tsx Submit ``` 我们可以看到`disabled`变成发`?disabled`,明确告诉解析引擎这是一个需要特殊处理的布尔属性 ### magix5中的布尔属性 magix5采用的是`html`属性`value`的处理,当属性`value`为`falsy`时,删除相应的属性 magix5前期在处理时,虽然采用的是`value`的处理,但是增加了语法,如``来表达当`checked`值为`trusy`时,保留`checked`属性,否则就删除。这样的写法有学习成本,好处是方便扩展其它语法,如非空语法,我们可以写成``来表达当`checked`为`null`或`undefined`时,则删除`checked`属性。...

前端技术

### inset 如果你有这样的样式`.full{position:fixed;left:0;top:0;right:0;bottom:0}`现在可写成`.full{position:fixed;inset:0}` ### overscroll-behavior 如果你有层叠的滚动容器,如果只想让用户滚动顶层的容器,即使滚动到顶部或底部也不触发底层容器的滚动,则可以使用`{overscroll-behavior: contain;}` ### scrollbar-gutter 如果你对容器设置`overflow:auto`,容器在出现和不现出滚动条时,通常会影响容器内的内容布局(常见于window系统),可以使用`{scrollbar-gutter: stable}`让浏览器始终保留滚动条的位置,它比`{overflow:scroll}`的好处是,如果不需要滚动条,不显示滚动条,仅保留位置,而`overflow:scroll`始终显示滚动条,即使不能滚动。 ### contain-paint 能隔离、提升一定性能的样式,具体使用可搜索一下 ### pointer-events 如果元素不响应任何事件,仅展示,那么通过添加`{pointer-events:none}`可提升性能 ### all 如果你在做一个带界面的插件放在别人的页面中使用,而插件自身又不想受到外界的样式继承干扰,则可以在插件的根节点上添加样式`{all:initial}`把所有继承的样式恢复到默认值,这样插件自身的界面就不会受宿主页面的影响了。 ### 全局鼠标样式 有时候我们做一些前端展示时,比如拖动,希望在按下拖动时,鼠标移到页面上任意位置都是拖动的样式,则可以这样做。 先增加一个css ```css .global-cursor * { cursor: inherit!important;...

方案

> 本篇不谈实现,只谈思路 ### 从父到子逐层渲染 如果我们要在当前`view`中渲染其它`view`,在`magix`当中我们这样写即可 ```html ``` `magix`在渲染上述模板片断时,采用仅`聚焦`当前`view`的思路,即渲染时,不关心也不会预处理子`view:./user/info`。而是把当前`view`的`html`片断真实渲染到页面上后,才会查找当前的子`view`,然后加载渲染。 这与其它的常见框架不同,比如`react` ```tsx ``` 因`react`编译成虚拟`dom`是类似这样的函数调用 ```tsx React.createElement('div',{class:"card"}, React.createElement(UserInfo) ) ``` 对于这样的代码执行,是先构建子节点,最后才构建父节点。基于这点,后续在`react`中比较容易实现的功能在`magix`当中均难实现。 不过有些功能在`magix`当中却比其它框架容易实现。 ### 不留痕迹 通常`view`背后都需要接口的支撑,即区块从`magix`开始加载、实例、展示是有时间差的,如果我们要在这个过程中添加一个`loading`动画,在`magix`中只需要像下面这样做 ```html ``` 在``标签间加入任何你想要的提示内容,在子`view`内容真正展示前,均会展示这个提示内容,这在做子`view`动态切换时非常有用,比如 ```html ``` 如果把`src`属性设置为一个变量,则`magix`会动态的根据变量的值去渲染相应的`view`。假设`dynamicViewPath`初始值为`a`,后变更为` b`,则在`a`到`b`的切换过程中,`magix`会在销毁`a`这个`view`后,把``标签间的内容恢复到渲染前的状态,如果你在``标签间加入了`loading`动画,此时会显示出来,等到`b`真正渲染后,`b view`的内容会把`loading`替换掉。这个过程是`magix`自动处理的,开发者只需要在``标签间写上相应的`loading`提示即可。...

方案
前端技术

attribute和property最早让人熟知应该是jQuery中的attr和prop方法吧,当初很多人分不清楚该在什么情况下用哪个方法,好像都可以。 https://stackoverflow.com/questions/5874652/prop-vs-attr 这里我们不再讨论它们之间的区别及使用场景,假设您已经熟知了这些基础知识。 我们接下来讨论下在当前流行的虚拟dom中如何控制和修改attribute或property #### 从attribute到property 有了数据驱动界面的开发思路,目前都是开发者操纵数据,数据+模板dsl交由框架完成界面的渲染。用户能控制的只是attribute,很少去操作property。 从attribute到property的映射环境会自动帮我们完成,比如 ```html ``` 一个禁用输入的输入框,添加disabled属性即可,通过读取输入框的property(disabled)可以得到true或false,获取是否禁用。而attribute中的值都是字符串,我们无法通过字符串的`true`或`false`表达输入框是否禁用,如 ```html ``` 输入框依然是禁用状态。如果非禁用,只能移除disabled这个attribute #### 常见框架是如何表达添加或删除attribute 以react为例,如果要表达删除一个attribute,它的值为false即可,这里之所以可以用flase是因为jsx,也即把dsl写在了js里,这个false不是字符串,如 ```jsx ``` 如果要表达任意的attribute添加或删除,需要这样 ```jsx ``` react中需要计算的attribute是不能用引号引起来的。 在magix中,因为dsl采用了标准的html,所以attribute都是使用双引号引起的。 如 ```html ``` 首先{{= epxr }}表达式表示输出内容,毕竟要有输出,拿到输出值后才能进行下一步的添加或删除attribute的操作...

前端技术

`magix5`的核心目标是高性能,同时要兼顾框架大小、开发者便捷上手体验等事情。 对于性能的处理,自然是`magix5`内部的事情,关键是看`API`如何透出给开发者使用。 在`API`的设计上,目标是简洁易用,对于初上手的用户来讲,只需要掌握很少的`API`即可完成简单的页面,而对于资深用户来讲,`magix5`依然能够提供足够的`API`去完成复杂的应用实现。 个人总结了下,对于`API`分为`显式API`和`隐式API` #### 显式API > 显式API指用户必须掌握的入门API,这类会反复强调,让用户掌握 比如对于一个`view`的实现,通常分为`样式文件(css或less)`、`界面文件(html)`及`核心执行文件(javascript或typescript)` ```css /*user.css*/ .user-name-card{ border:solid 1px #ccc } ``` ```html name card ``` ```ts import Magix5 from 'magix5'; let {View,applyStyle}=Magix5; applyStyle('@:user.css'); export...

方案

> 文章在2019年写的,从内部转载公布于此 ### 前言 经过几年的努力,阿里妈妈所有基于`magix`技术开发的管理系统、运营平台、营销页面等,均被统一成了[magix运行环境]+[各自的业务`view`],在整个推进过程中,`magix-cli`功不可没 #### magix运行环境 > 运行环境包括以下几个部分 1. 模块加载器,如seajs 2. 基础类库,如jQuery 3. `magix`核心代码 4. `magix`组件库 5. `web components`组件 #### 业务view 各业务线为了完成自己的业务需求而实现的自己的view > 因为有了`magix-cli`,各系统、平台、营销页面之间,除了业务`view`不同外,`magix`的运行环境是一致的,这也给接下来的`magix`项目间加载打下了基础 ### magix项目间的互相加载与渲染 项目间的加载在技术上没有难点,更多的是在业务上,比如有些`view`是登录后才能访问的,有些`view`可能挂载一些特定的权限等,因此我们除了技术外,在项目中约定了一些规则。 1. 各项目间的业务`view`需要继承自己的基类`view`,在基类`view`中完成如请求、挂载等事情...

方案
前端技术

> 独立是为了更好的协作,微应用、模块之间应该是互相独立的、隔离的、自洽的。 ### 隔离内容 #### 样式隔离 现在不管是react,vue还是我们的magix,都有样式scoped功能,所以在不使用iframe隔离的情况下,我们应该使用样式scoped功能来进行隔离 #### DOM隔离 每个应用或模块只在自己所处的容器节点折腾,允许向document或body上添加节点,但仅限折腾自己添加的节点,并在生命周期结束时,移除自己添加的节点 #### js隔离 使用环境提供的模块加载机制进行隔离 #### 路由 每个应用管理自己的路由,不管是hash还是history,理论上不做限制,后续我们将和后端一起,让后端在任意url的情况下,均输出合适的内容,理论上不会再有服务端的404出现,把404交与前端控制 > 宿主应用或模块可能要注意子应用或模块操作路由时,自己该如何做相应的响应,遇到问题再具体分析 ### 共享内容 #### 基础模块 对于同技术栈的项目是否需要把项目中使用到的基础模块在同一个仓库维护,使用同一个cdn版本号? > 对于同技术栈的微应用或模块,像magix的跨项目mount view,大家使用的magix,accouting,moment其实是一样的,通过import-map我们可以把各项目中使用的这些模块配置成同一份,可以有效的减少重复加载。 即使是非同一个技术栈的,面向未来,使用环境提供给我们的模块加载、管理机制,比如浏览的import,import-map功能,我们也可以跨技术栈使用同一份模块。 这些基础模块我们该如何维护、升级、共享? 样式模块 样式一定要共享的是基础颜色,可参考这里:https://thx.github.io/magix-gallery/#!/all/edit/index...

方案
前端技术

### 分类 > 在magix项目中,样式被分为以下3大类 #### view样式 view样式是配合当前区块而存在的样式,编辑器会对样式内容做编译,样式范围仅在当前view中生效,不会影响到其它view。 在`javascript`文件中,通过`applyStyle`进行关联,如 ```ts import Magix5 from 'magix5'; Magix5.applyStyle('@:./user.less'); ``` 如果样式文件中定义的样式没有被使用,则编译器会给出提示,同样的,如果html中按一定规则找不到选择器定义在哪个样式文件中,同样会给出提示 #### 项目全局样式 通过对编译器配置`scopedCss`,指定当前项目中使用的全局样式,这个`全局样式`是会被编译器编译转换的。 如 ```ts magixConposer.config({ scopedCss: [ './tmpl/g.less', './tmpl/app/test.css' ] }); ``` 这个样式文件之所以要提前通过配置的方式告诉编译器是因为:编译器需要对整个项目作编译后,才能给出哪些样式没有被使用到,或`html`中使用了哪些未声明的样式,因此在编译之前就需要知道哪些文件是`项目级别的全局样式`...

方案
前端技术

> 前端是和界面打交道的,这里讨论的“无界面”是一种平时开发和思考问题、提供解决方案的一个倾向 现在的前端都是采用数据驱动界面或数据描述进行开发的,这会在一定程度上导致"数据不够纯",比如为了达到某些界面效果,在数据中定义了一些和业务无关的界面数据。 同时,在一段时间内业务通常是稳定的,而界面却不一定,有时候为了适应大众需要,界面可能会变来变去,如果把界面和背后的逻辑控制层及数据互相独立,那在一定程度上可缓解这些问题。 类似现在的前后端分离,分离后大家只需要聚焦接口即可,如果数据不对,则后端修改,如果界面不对,则前端修改。定义好界线后才能更好的发挥各自的效率。 以聊天系统为例,假设我们要做这样一个聊天系统:https://xinglie.github.io/magix-talk/ 如果我们要求:不考虑界面,只实现一个对象,这个对象提供如好友列表、群列表及最近聊天列表,同时有新消息进来时,内部进行封装转换,然后再统一对外输出:好友变化、群变化、聊天窗口对象的打开和关闭等业务逻辑。 如果只实现这样一个纯`API`形式的对象,是不是会容易很多? 如果我们要求:只考虑界面,不考虑背后的聊天数据,只把这个界面做出来,同时可以根据外界的数据变化,更新相应的界面即可。 如果只实现这样一个纯界面,是不是会容易很多? 完成上面`2`部分后,我们把它们接合起来,是不是就是一个完整的应用? 当我们需要其它界面,如移动或小程序时,我们仅需要去做一套界面即可,背后的聊天这个纯`API`的对象是共用的,这样后期如果是业务发生变化,只需要修改这个纯`API`对象 当我们在某些时候,需要编程的方式进行控制,比如在聊天页面:https://xinglie.github.io/magix-talk/ ,以编程的形式打开与某人的聊天 我们可以这样 ```ts MTalk.open('user001'); ``` 而这里`MTalk`对象提供的`API`,即是前面这个纯`API`的对象提供的,也即是当我们有了这个纯`API`的对象,我们也有了与其它开发者合作的`API`。后期不用为了合作再单独开发。 我们可以看到,在这个例子里,重要的就是这个纯`API`的对象的实现,它应该定义清晰输入和输出。 输入:什么样的初始数据,什么样的消息,某个数据的变化会引起其它数据怎么变化 输出:统一的好友、群等列表,新消息的通知,其它信息变化的通知等 同时这个纯`API`的对象应该是轻量高效的,不应该存储其它与业务无关的数据。 我们把界面对象和业务逻辑处理对象分开,也可以让我们的前端开发更专注:有些人偏界面实现,有些人偏逻辑的处理。类似前后端分离的方案,我们把界面和业务逻辑也进行了分离。 在我看来,未来界面实现会变得更容易,有各种框架、组件库的支持,甚至浏览器都可以内置这些框架和组件,所以界面实现会变得越来越容易,但有一点是无论如何也做不到的,那就是你的业务数据和逻辑。 我们应该把重心放在数据和逻辑的处理上,即减少界面研究的精力投入,把我们的应用变成一个个“无界面”的应用,以此来适应未来界面的升级和重构,以及多种终端。

方案
思考
前端技术

> 接上篇《前端交互之立即响应》https://github.com/xinglie/xinglie.github.io/issues/93 个人认为在`API`设计上有些`API`也是需要做到立即响应的,不能有异步等其它非及时响应的流程或过程,销毁就是其中之一 销毁无非分以下几类 ### 用户级别 用户主动关闭一些内容,比如用户主动关闭了视频播放器,关闭了`Excel`窗口等,那么这些关闭的动作就是销毁`API`的调用,除了必要的关闭提醒外(如:文件内容未保存,是否离开?),开发者在实现`关闭`这个销毁`API`时,就需要立即响应执行,否则用户点了关闭按钮,窗口还在那里展示,会是一个什么样的体验? ### 开发者级别 做为应用的开发者(程序员),我们免不了会使用一些第三方的组件或插件,当我们需要销毁这些组件或插件时,肯定希望这些组件或插件立即销毁,否则我们调用了相关的关闭或销毁方法,组件或插件的实例还一直存在,是不是让人抓狂? ### 系统级别 当系统资源不够时,会自动关闭一些不太活跃的应用,我们在系统自动关闭时,也需要立即响应,不应有阻止自动关闭的动作在里面 以上是从提供方的角度,即`API`设计者的视角来讨论的,即提供方在涉及销毁的`API`上应该是立即执行,不应该有异步的存在。因为一但有了异步的存在,调用方也必须以异步的方式调用,会导致整个链路上都使用异步。 那如果从使用者的角度,在关闭或销毁时想使用异步怎么办?比如用户点击关闭按钮,播放一个动画后再关闭。 这个权力应该交与调用方控制,如果调用方想在关闭前播放一个动画再关闭,则关闭时通知调用者,调用者播放动画完成后再调用真正的销毁,这个事情在调用方里做,不在提供方里做。

思考