SegmentFault 前端之路最新的文章
2021-01-01T19:47:09+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
低代码实战篇一:建立认知与深挖业务
https://segmentfault.com/a/1190000038772873
2021-01-01T19:47:09+08:00
2021-01-01T19:47:09+08:00
leonleung
https://segmentfault.com/u/leonleung
8
<blockquote><p>笔者自2020年5月底入职新公司以来,一头扎进公司低代码平台的建设中。从零开始,在实践中不断打磨,也总结了不少经验与教训。在此,希望能抛砖引玉,给各位大佬带来更多新的思考。</p><p>本系列计划分为四篇,逐步讲解低代码平台建设实践中的各种问题和解决办法:</p><ul><li><strong>低代码实战篇一:建立认知与深挖业务</strong></li><li>低代码实战篇二:结合具体业务产品谈谈实现</li><li>低代码实战篇三:围绕现有能力不断拓展产品形态</li><li>低代码实战篇四:总结与展望</li></ul><p>本篇为开篇,按照是什么、为什么、应怎么做的结构来展开,大约需要八分钟的阅读时间。</p></blockquote><h2>引子</h2><p>笔者从事前端六年,其实也就是今年才对低代码相关概念和思想有所了解,但是不知觉中运用到低代码模式来进行开发却早在16年初就开始了。</p><p>当时笔者作为部门内前端小能手,接手了一个即使在现在看也是相当麻烦的项目。这个项目的目的在于定期以<strong>表格</strong>的形式收集审核成员公司的报表,汇总给集团高层和相关分析部门查看。刚接手时笔者想着不就是建几个表单,填写、提交、审核、查看一条龙完事儿了嘛。</p><p>结果后面一对接需求才傻了眼,集团下有上百个成员公司,归属于数个版块集团公司,每个版块集团负责统一收集版块内的关键运营指标数据并上报。但是每个板块的业务大相径庭,汇总的表格格式、数据绝大部分都不一样!!每个业务版块平均十多张表格,多的时候总共<strong>六七十个完全不一样</strong>的表格!!这还不是最可怕的,最可怕的是由于业务变化频繁,这些表格还会经常变动!!而且还要能支持在移动端完美的展现表格数据(移动端展现大表格的体验极差)!!</p><p>做过业务系统的童鞋们都知道,数据库里维护六七十个业务表是非常麻烦的,业务表字段要是频繁的改动那更是没办法做。前端童鞋也很苦逼呀,几十个表单页面改来改去,那不得原地爆炸。</p><p>时间紧急,第一版开发时间只有一个月,苦思数日的我终于想到了一套在当时看来解了燃眉之急的解决方案:</p><ol><li>每个表格用一个json对象来描述,大概如下:</li></ol><pre><code class="json">{
row_01: {
column_01: {
rowspan: 0,
colspan: 0,
editable: false,
type: 'string',
value: '业务',
...
},
column_02: {
rowspan: 0,
colspan: 0,
editable: false,
type: 'string',
value: '指标',
...
}
},
row_02: {
column_01: {
rowspan: 0,
colspan: 0,
editable: false,
type: 'string',
value: '净现金流',
...
},
column_02: {
rowspan: 0,
colspan: 0,
editable: true,
type: 'number',
value: '',
...
}
}
}</code></pre><p>这是一个2 X 2的表格,实际业务中的表格要远远复杂得多,但是通过一个精心设计的 <strong>json schema</strong>,总能完备得描述这个表格长什么样子,哪几行是表头,单元格要跨几行跨几列,哪些单元格是不可改的,哪些单元格是可改的,可编辑单元格的内容类型(字符串、数字、时间点、时间段、金额等等)</p><p>2、PC端展现表格时基于json schema做渲染,伪代码如下:</p><pre><code class="html"><table>
<tr v-for="row in jsonSchema">
<td
v-for="cell in row"
:rowspan="cell.rowspan"
:colspan="cell.colspan">
<span v-if="!cell.editable">{{cell.value}}</span>
<template v-else>
<input v-if="cell.type==='string'" v-model="cell.value" />
<input-number v-if="cell.type==='number'" v-model="cell.value" />
<date-time v-if="cell.type==='dateTime'" v-model="cell.value" />
...等等其他类型输入项
</template>
</td>
</tr>
</table></code></pre><p>没错,核心代码就是这么简单。。</p><p>3、移动端定义一系列适用于移动端的组件,比如主副标题、指标详细(左右结构、上下结构),根据不同业务类型对数据展示的不同需求,基于 <strong>json schema</strong> 转换成另一套 <strong>mobile dsl</strong>(<a href="https://link.segmentfault.com/?enc=B3hGTPG5bex9lAfZgMXYUA%3D%3D.Hg7ExqJMRJppwbAB3bEpJGb1qqpNL1vNlX6hItBk%2B04%3D" rel="nofollow">什么是DSL</a>),再基于 <strong>mobile dsl</strong> 和移动端组件生成一系列组件的组合。比如:<br><img src="/img/remote/1460000038772876" alt="" title=""></p><p>这样的显示在移动端上就比表格的形式舒服多了~</p><p>转换后的<strong>mobile dsl</strong> 大概是这样的:</p><pre><code class="json">[
{
type: "section",
title: "财务指标",
subTitle: "万元",
list: [
{
type: "description",
layout: "horizontal",
title: "净现金流",
desc: "1000"
},
...
]
},
...
{
type: "introduction",
intro: "XXXXX"
}
]</code></pre><p>渲染的伪代码我就不写了,也挺简单的,</p><p>4、每个表格定制一份 <strong>json schema</strong> 作为表格模板,填报人每个填报周期都可以此模板为基础填写表格,某个填报周期如果表格发生了变动,只需要调整表格的 <strong>json schema</strong> 和根据具体的修改,更改移动端 <strong>mobile schema</strong> 即可。只需要一个数据表,就能解决以往几十上百个数据表才能解决的问题~后续经过统计,增增改改至少有两百个不同版本的复杂表格。。。</p><p>现在回看当时这个<strong><em>初级</em></strong>项目,尽管还有许许多多的问题,比如由于项目投入和人手经验能力的问题,未能做到图形化输出json schema,完全是靠的人力手工输出哈哈。。还比如表格版本管理功能逻辑混乱等等。但是这是我第一次独自一人从需求调研到产品设计到数据库表设计再到前端开发后端监督再到项目管理,完整的掌控一个项目,各方面都有了较大的提升。</p><p>如果当时项目投入再大点,完善基于<strong>图形化界面</strong>输出 json schema 的功能,基本就是一个比较标准的低代码类应用了。可惜经费不足、人手不足,只能做到手撸json的阶段。不过这个项目也为我积累了很多宝贵的经验,毕竟从需求调研、产品功能设计、数据库表设计再到前端开发后端监督等等我都有极大程度的参与。</p><h2>low-code低代码到底是什么?</h2><p>所以低代码到底是什么呢?看了我刚刚举的例子,可能大家已经有了一个初步的概念。在这我根据自己的理解,做一下归纳总结。</p><p>低代码是以<strong>效率提升</strong>为目的,通过图形化配置、少量参数配置、内置隐含逻辑规则等方式,输出能够完全描述业务模型且能够兼容代码编写的数据,并以此根据业务或产品形态,完成应用的构建与渲染。</p><h4>以效率为目的</h4><p>一是为人而服务,不仅是提升开发人员的效能,更要能给业务应用所关联的所有人员提供效率提升的保障。二是为业务而服务,营销页面低代码平台快速搭建营销页面,场景应用低代码平台快速输出应用,流程表单低代码平台快速输出功能逻辑完备的表单流程等等。</p><h4>图形化配置、少量参数配置、内置隐含逻辑规则等方式</h4><p>蕴含着一个低代码平台的一个重要核心,那就是<strong>门槛一定要足够低</strong>,简单易懂的操作方式,所见即所得的操作体验,低代码甚至完全不需要写代码的低要求。</p><h4>输出能够完全描述业务模型且能够兼容代码编写的数据</h4><p>这要求能够对业务持续进行深入的分析,对业务的全貌具有充分的了解,低代码平台适合较为垂直的业务领域,过于追求大而全,低代码可能反而成为阻碍。</p><h4>根据业务或产品形态,完成应用的构建与渲染</h4><p>通过我上面项目的例子,很好理解,输入的是表格,输出的不一定也是表格,可能是适合移动端展示的样式,也可能表格数据经过BI输出适合大屏展示的可视化图表。展现形态(pc、mobile、大屏等)、数据载体(单一数据,结构化数据,BI处理的数据)、平台特性(安卓、iOS、小程序、h5等)等都对低代码平台有较大影响,我们必须结合实际业务深入分析。</p><h2>为什么要做低代码平台呢?</h2><p>因为业务需求,也因为成本效率更高,更因为从长远上,低代码已经成为一种趋势。对于技术团队或者个人,结合业务尽快接入或者了解,有利于在细分领域迅速占有技术优势。对于企业,对于定制化需求不是特别高的业务,低代码平台能较好的增效赋能。</p><p>当然,我反复强调业务,一定要结合具体的业务来思考当前是否需要开发或者接入一个低代码平台。</p><p>但是,提前了解了解也蛮好~</p><h2>低代码平台应该怎么做呢?</h2><p>接下来的系列文章中,笔者将结合公司的低代码平台产品—一款通过图形化拖拽和简单参数配置就能生成Andriod、iOS、支付宝小程序、微信小程序四端UI一直、体验一致、功能一致的应用—来谈谈这个产品是怎样从无到有一步步建设而来的。</p><p>主要内容包括但可能不限于:</p><ol><li>业务分析与抽象</li><li>数据模型与组件抽象</li><li>动态数据赋能</li><li>可用性、易用性和满足更定制化的需求</li><li>拓展运营和开放的能力</li></ol><p>欢迎大家在评论区交流,如有错误也请指正哈。</p><p>感兴趣的朋友欢迎点赞关注,年底KPI就靠各位大佬啦。我将在元旦放假期间尽快完成全部文章,尽快发出~</p>
Array.prototype.slice.call 将伪数组转成真数组的原理是什么?
https://segmentfault.com/a/1190000017292302
2018-12-07T10:10:21+08:00
2018-12-07T10:10:21+08:00
leonleung
https://segmentfault.com/u/leonleung
19
<p>好久没上SF,昨天上来看到一个<a href="https://segmentfault.com/q/1010000017279736">问题</a>,引起了我的兴趣。一番探索和研究后,有了此篇文章,也算是对该问题的解答。</p>
<pre><code>let pretendArr = {0:0,1:1,2:2,length:3};
[].slice.call(pretendArr); //[0,1,2]</code></pre>
<p>请看上面的例子<br>可能很多前端童鞋都很知道 Array.prototype.slice.call 可以用于将类数组对象转为数组,call 和 apply 的用法和作用网上一搜一大堆。<br>在这里主要是为了让 pretendArr 借用Array构造函数原型上的 slice 方法,并且改变 slice 方法里的 this 的指向。<br>所以这个问题其实不在于 call 或者 apply,关键在于 <strong>Array.prototype.slice</strong> 这个方法上。</p>
<p>slice这个方法是js原生方法,自然而然,我会想到去找找 es 的规范,看看这个方法是怎样定义,以及如何实现的。</p>
<p>以下是es对该方法定义的截图,图片看不清楚的童鞋可以看看<a href="https://link.segmentfault.com/?enc=sumVJ9hIuSzhMxwJrH2H0Q%3D%3D.EYDOdRDzTEZPbHYSf%2FSFFZHwO%2BN1FNj%2Bzphm%2FeGlXifZwah%2Bbr%2FHxuKCLuCLr4%2Fz" rel="nofollow">链接</a><br><img src="/img/bVbkGyG?w=1392&h=2082" alt="图片描述" title="图片描述"></p>
<p>嫌英文字母太多的可以直接看以下我写的slice方法的伪代码:</p>
<pre><code>Array.prototype.slice = (start, end) => {
let O = ToObject(this)
let A = new Array()
let lenVal = O.length
let len = ToUnit32(lenVal)
let relativeStart = ToInteger(start)
let k, final, relativeEnd
if (relativeStart < 0) {
k = max(len + relativeStart, 0)
} else {
k = min(relativeStart, len)
}
if (end === undefined) {
relativeEnd = len
} else {
relativeEnd = ToInteger(end)
}
if (relativeEnd < 0) {
final = max(len + relativeEnd, 0)
} else {
final = min(relativeEnd, len)
}
let n = 0
while (k < final) {
let Pk = ToString(k)
let kPresent = O.hasOwnProperty(Pk)
if (kPresent) {
let kValue = O[Pk]
Object.defineProperty(A, ToString(n), {
value: kValue,
writable: true,
enumerable: true,
configurable: true
})
}
k++
n++
}
return A
}</code></pre>
<p><a href="https://link.segmentfault.com/?enc=UdrQR7cdaCggj6FRYBsY0A%3D%3D.4HS%2BuOaJSHDHm6fwkPeRJyHia8hEFAXYXTtEjp4EMS8%3D" rel="nofollow">ToObject</a>、<a href="https://link.segmentfault.com/?enc=RpvyPr1vdgKkvG8vnMYCiA%3D%3D.EAfxF1qhvFlX5g0bYNfvBpxtPcjluv%2BISXh70EYrRs0%3D" rel="nofollow">ToUnit32</a>、<a href="https://link.segmentfault.com/?enc=CHpdf1y5EpzcbgPAcowWFw%3D%3D.%2Fxw2wz4ch262uX3pWHe2vRwy5rV5ezSq2FfuyuR7Dcg%3D" rel="nofollow">ToInteger</a>、<a href="https://link.segmentfault.com/?enc=yA1CJOPYGonRvBqJf94GDw%3D%3D.%2FKV2YaP4pKfU0IkPEf3xFOZ4%2B4POXEAFUWyAujsd%2FNI%3D" rel="nofollow">ToString</a><br>slice 方法不要求 this 必须是数组,因此类数组对象也可以调用该方法,在本例中入参 <strong>start</strong> 和 <strong>end</strong> 均为 undefined,实际上是根据 类数组对象 的 <strong>length</strong> 属性,从0到length-1去把类数组对象对应的值取出来,放到前面声明的数组 A 里,最终再return A<br>因此,类数组对象的 length 属性很重要,并且该对象里的数序也很重要,都会影响到转换为数组的结果。如以下例子:</p>
<pre><code>let pretendArrA = {0:0, 1:1, 2:2, length:2};
[].slice.call(pretendArrA); //[0,1]
let pretendArrB = {0:0, 2:2, length:3};
[].slice.call(pretendArrB); //[0, undefined, 2]</code></pre>
<p>第一次写文章,想到哪写到哪,写得有点乱,各位看官勿怪,如果对你有用,还请点个赞~</p>