美文网首页
前端学习方法空谈

前端学习方法空谈

作者: _刘小c | 来源:发表于2018-12-11 15:51 被阅读0次

写在前面

在大公司里, 你总是会被明确的分工到某个螺丝坑中,重复的拧着同一种型号的螺丝。 当然这里带来了利与弊, 弊端很明显, 就是无法再接触所谓的工作中学习,毕竟你一直做着同样的事。 但是另一方面,善于总结的人,总是能因此点满了某一项专精,比如ui控件大佬,比如css大佬, echart大佬。 这些大佬会沉淀出一种叫轮子的东西,供他人使用。
所以在大公司里,你往往可以看到一些相对不是很成熟,但是又有一些精髓的轮子再反复使用。比如UI组件,SDK,认证服务等。和github等开源社区上的资源相比,这些轮子离我们更近,开发人员能力也和我们在一定程度上更接近,而且由于公司的推动,你将更多的更有机会的去接触他们,学习他们。我们不但需要快速上手这些工具,还要快速了解其原理,巧妙的通过一些demo快速掌握这些套路,总结。让其成为自己的另一种学习途径,在大公司里的特殊途径,尤为重要。

大致思路

Leech: n. 吸血鬼; 榨取他人利益的人 vt. 依附并榨取

这边我用leech这个词,是很贴近本文的意图的。 因为我们不断的接触这些工具轮子,所以可以有很多的时间,将他人沉淀的轮子,融为自己的知识,让自己变成更健壮。

轮子: 可以解释为套路,模式,工具,一切经过总结出来的东西

新轮子
=》 思考熟悉的那一面,脑海里产生第一印象,它可能是什么
===》复制黏贴,看看和你想的是否一样,异同点在哪儿
======》 找到它的关键节点,改一改关键元素,猜猜他的结果会有什么改变, 甚至可以试着做一个demo
=========》 参考答案瞄一眼(源码),如果有机会有时间,可以观摩一下大佬的代码嘛。不过如果demo跑通了,其实看不看问题不大
============》 思路,方法,套路,原理 Get, 细节 实现过程 IGNORE

简称:copy - try - modify

小小的例子

bootstrap()
  .ns('AE-DOC')
  .theme(MyTheme) // 注册并使用主题
  .req(require.context('./modules', true, /(?:index|404).jsx?$/))
  .mount()

这是一个初始化ae的bootstrap,给我的第一印象就是$(li').eq(0).sibling().addClass('xxx').value
像jQ一样的链式调用,很舒服很实用

bootstrap()
 .ns('AE-DOC')
 .mount() // 先mount
 .theme(MyTheme) // 注册并使用主题
 .req(require.context('./modules', true, /(?:index|404).jsx?$/))

试着改了一下顺序,这个链式调用果然失败了,因为mount就是他的终点。然而改变其他方法的顺序,并没有问题。

引出两个问题:

  1. 为何可以如此的链式调用,有的时候失败有的时候成功
  2. 这种写法的意义是在哪里

所以我拿开始想到的jQ做了对比,jQ中间的链式调用,是为了展示一个过程,找到最终想要的 jQ元素,而之所以能链式调用,是因为每次返回的都是一个jQ过的对象。

相同原理的东西其实还有, 比如:moment().subtract(1, 'days').add(1,'days').format('YYYY-MM-DD')

试着跑一个类似原理的Demo:

// 一个api拦截器 处理一些body和params的
class NomorlizeConfig {
  constructor (config) {
    this.config = config
  }

  paramsTrans = () => {
    // ...转化configParams
    this.config.params = transParams
    return this
  }

  dataTrans = () => {
    // ...转化body
    this.config.data = data
    return this
  }

  // 添加某些config
  addConfig = (config) => {
    this.config = Object.assign(this.config, config)
    return this
  }

  get value() {
    return this.config
  }
}

// 继承了bootstrap链式调用的特性
newConfig = new NomorlizeConfig(config)
              .paramsTrans()
              .dataTrans()
              .addConfig({needSuccessMessage: '新增人员成功'})
              .value

以上,我已经get到bootstrap的链式调用精髓所在,而且我leech出了自己的demo,很舒服很实用

经典表单表格模式

什么是模式?

减小相似交互逻辑页面的重复性开发工作。 DRY原则

设计模式中的 Pattern:模式是解决某一类问题的方法论,把解决某类问题的方法总结归纳到理论高度,那就是模式

AE 中的模式:既包括数据层面的,对数据(state)和基于这些数据操作(actions/reducers)的封装;也包括 UI 上的,对数据展示和操作在 UI 上的封装,是针对某一类问题的解决方案。

总结一下,这里本没有路,人走多了就有了路

这个模式其实就是我前面说的,一群大佬点满了某项专精以后,总结出了一种特定的模式

有时候,模式会依赖一些DSL语言。

Domain Specific Language)是一种用来解决特定领域问题的计算机编程语言我们经常使用的CSS、SQL都属于DSL。

简单来说,DSL语言是在高级语言之上,更容易理解的语言。

AE就是用了某种设计语言,理论上你了解了其中的语法,使用起来就很舒服了。

表单模式
export default ({ctx, scope}) => ({
  permission: -1,
  name: '经典表单',
  model: 'Form',
  actions: { 'show': (entity) => showSubmitData(entity) },
  reducers: { show: (state, payload) => state },
  source: { uri: '/basic', agent: () => Promise.resolve({field_1: '123123'}) },
  schema: {
    field_1: { label: '单行文本字段', type: 'string', required: true, },
    field_2: { label: '多行文本字段', type: 'string', component: 'FieldTextArea',
      componentConfig: { autosize: { minsize: 10, maxsize: 40 }}
    },
    field_3: { label: '自定义字段', type: 'string', component: SimpleField }
  },
  decorators: {
    config: {
      onLoad: 'get', // 打开表单时,触发请求,从服务端获取数据
      onResponse: noop,
      buttons: [
        {label: '重置',action: 'reset'},
        {label: '提交数据', style: 'primary',action: 'show'}
      ]
    }
  }
})

以上是AE的最基本的表单模式DSL,忽略掉他封装的reduxSource部分,我们抓住他的核心,schema(一般是DSL里篇幅最大的部分),我们称之为root。
如果你完全没有见过类似的配置型语句,那也没关系。其实你一定见过了,只是你想不起来。
我们根据root简单的来造个demo。

核心是一个表单, 那么他应该长这样的。

render() {
    const { getFieldDecorator } = this.props.form
    const schemas = this.props.fields || []
    return (
      <Form layout={defaultFormLayout.form}>
        {
          schemas.map(schema => {
            // 分解构造所需的config. 未知的restConfig会自动向下传递
            const { key, rule, label, field, onChange ...restConfig } = schema
            const Component = Fields[field || 'Input']
            return (
              <FormItem
                {...defaultFormLayout.formItem}
                label={label}
              >
                {
                  getFieldDecorator(key)(
                    // 为每个函数绑定this
                    <Component 
                        onChange={onChange.bind(this)} fieldConfig={{...restConfig}} />
                  )
                }
              </FormItem>
            )
          })
        }
      </Form>
    )
  }

通过schema形成一个基本表单样式,然后把需要的东西一点点的拆解开来,放在合适的位置。

比如:

  1. label,component可能对应表单的label和渲染的组件名称
  2. onchange用来绑定表单上的可能事件,注意,这里开发者可能会友好的为你绑上this,以让你更好的使用组件内部的东西
  3. restConfig可能就插在组件里向下传递,提供给使用者埋点

在基础的表单架构上,AE的DSL是利用装饰器给表单组件做进一步的丰富的。
其实decorators就是高阶函数和HOC,decorators就可以理解为为基础组件添砖加瓦,多穿几件衣服。

所以理解decorators后,其实你可以很轻松的为自己的刚才的demo搞一个modal的decorators

// 自制修饰器modal
@modal
class demoForm {}

也可能提供一种内置的修饰器,只要传入相关的option

// 这边传入button 就能直接修饰表单的footer
 footerFactory = () => {
    const defaultButtons = [
      { label: '确定', type: 'primary', key: 'ok', action: 'onOk' },
      { label: '取消', key: 'cancel', type: '', action: 'close' }
    ]
    const buttons = this.props.buttons || defaultButtons
    return buttons.map(button => {
      // 同样的button事件绑定,通过判断actionType动态绑定
      const onClickEvent = typeof button.action === 'function' ?
        button.action.bind(this)
        : this.props[button.action] ?
          this.props[button.action].bind(this)
          : this[button.action]
      return <Button type={button.type} key={button.key} onClick={onClickEvent}>{button.label}</Button>
    })
  }
表格模式
export default ({ctx, scope}) => ({
  permission: -1,
  model: 'Grid', // 经典表格
  componentConfig: {
    checkable: true,
    selectType: 'radio',
    bordered: false
  },
  schema: {
    name: {type: 'string', label: '姓名'},
    age: {type: 'number', label: '年龄'},
  },
  decorators: {
    detail: false,
    search: false,
    edit: false,
    del: false,
    list: false,
    create: false,
    paginate: { showQuickJumper: true, $limit: 3 },
  }
})

横向比较表单和表格,其实你已经领悟到该DSL的大致语法了。
同样从schema入手,创建一个基本表格:

render () {
    const { items = {} } = this.props.dataSource || {}
    // 转换schema对象为数组columns
    const { columns, primaryKey } = this.normalizeColumns(this.props.columns)
    // 转换items对象为数组dataSource
    const dataSource = this.normalizeTableItems(items)
    return (
      <div className='baseTable'>
        <Table
          rowKey={record => record[primaryKey]}
          columns={columns}
          dataSource={dataSource}
          onChange={this.onTableChange}
          pagination={this.paginationFormat()}
        />
      </div>
    )
  }

这边把schema对象在最后渲染时才做转换为数组,为了在算法性能上尽量的去避免对数组的for循环,也是一个可以学习的点。

这是自制的demo:

export default (props) => {
  const columns = props.columns
  const option = {
    columns: columns,
    source: 'dataSource',
    action: 'submitParams',
    decorators: ['filter']
  }
  return (
    <div>
      <BaseTable {...props} option={option} />
    </div>
  )
}

// 关于修饰器
    const { decorators } = this.props.option
    this.final = Base
    decorators.forEach(decorator => {
      if (decorator && typeof decorator === 'function') {
        this.final = decorator(this.final)
      }
      if (decorator && typeof decorator === 'string') {
        if (decoratorsCore[decorator]) {
          this.final = decoratorsCore[decorator](this.final)
        }
      }
    })

当你把demo造好以后,其他的配置项其实和表单没有什么不一样,同样是在你觉得可以插入的地方插入你想要的东西。当然和设计者是略有出入的,可能是它的组件不够强大,也可能是其他方面的考虑。

总结

  1. 没有魔法, 一切靠猜, 越猜功力越深厚
  2. 不要试图钻研底层源码,虽然那很有用,但是通常没有注释的代码会让你抓狂且费时。尝试自制Demo
  3. 如果你用AE模式,尽可猜根溯源;如果你用自定义组件,用你的方式仿造aE

学习延伸

以下, 是我根据ae的表格表单套路,造出的一个简单的echart模式。想法灵感来源于AE模式

    // 线图
    lineOption = {
      type: 'line',   // 定义图表基础type
      option: lineBaseOption,  // 传入配置好的图表option
      plugins: ['tooltip']  // 图表插件定义, 如tooltip, legend等, 需要在图表配置中加入相关option
    }
    // 饼图
    barOption = {
      type: 'bar',  // 定义图表基础type
      option: barBaseOption, // 传入配置好的图表option
      dataHandler: barDataHandler // 组件有默认的数据处理函数,如要替换,请再此引入
    }

其实和我自造表单,表格并没有什么区别,一样是很简单的原理, 把helloworld跑通了。 留下了大量的可配置空间

当你了解了这种工作模式, 我觉得上手vue应该也不是什么难事

var view = new Vue({
  el: '#app',
  data: {
    name: 'vue',
  },
  template: `<div id='app'>hello {{data.name}}</div>`
})

相关文章

  • 前端学习方法空谈

    写在前面 在大公司里, 你总是会被明确的分工到某个螺丝坑中,重复的拧着同一种型号的螺丝。 当然这里带来了利与弊, ...

  • 2019-01-17

    前端学习路径和方法 适合自己的前端学习方法前端技术的知识架构理解前端技术背后的核心思想 推荐入门 :《js高程》《...

  • 七周从前端入门到前端开发工程师

    作为一名大三开始学习前端,如今已经工作三年的前端狗,跟大家谈谈我的前端自学之路,以及自己的学习方法,和前端学习资源...

  • 2021年怎么自学前端?

    作为一名大三开始学习前端,如今已经工作三年的前端狗,跟大家谈谈我的前端自学之路,以及自己的学习方法,和前端学习资源...

  • CSS绘画大师的作品

    更多内容、学习方法,前端技术,请关注公众号:【web前端教室】回复:资料,得到一整套【JavaScript核心与实...

  • vue添加全局方法

    更多内容、学习方法,前端技术,请关注公众号:【web前端教室】回复:资料,得到一整套【JavaScript核心与实...

  • 前端学习方法

    前端工作流程是从UI处得到原型图或者效果图,在项目(网站、微信公众号、小程序、webAPP)中还原图片效果,然后和...

  • 三年前端面试经验加感悟(干货分享)

    我目前是在职前端开发,如果你现在也想学习前端开发技术,在入门学习前端的过程当中有遇见任何关于学习方法,学习路线,学...

  • 前端学习路线图(新手必备)

    前端开发是当下IT行业内热门的技术之一,这也引发了一股前端学习的热潮。那么,该如何学习前端呢?首先,好的学习方法很...

  • 反思

    想想之前只是空谈理论,没有具体的规划执行,对自己建立的学习方法并没有进行整体的运用,这就是计划管理出现了问题,以前...

网友评论

      本文标题:前端学习方法空谈

      本文链接:https://www.haomeiwen.com/subject/iohehqtx.html