文章预览
写业务,对于一个前端而言,应该是再正常不过的事了,业务对标着需求,前端 er 们根据产品的需求以及设计师的设计稿开发出相应的 web 应用,无论是一个简单的页面或是一套复杂的系统,或多或少掺杂着业务逻辑。然而,我们有时候写的业务逻辑到底是为了去写业务逻辑而写的吗,作为一个常年与业务抗战的骚 nian,我认为我们写的业务不光光是为了在排期内完成简单的任务,而是要打磨自己写业务的能力,并学会根据实际场景去设计一套灵活的,可维护,易理解的业务代码。
那以上所说的 “实际场景” 到底指的是什么场景呢,答案并不唯一,往往自己实践中碰到的难题都可以是一种场景,我们要学会理解这些场景。当然,场景不光归结于产品的 prd,而且往往还跟后端的提供的数据结构着密切的关联,夸张点的比喻就是,好比产品需要一道集色香味俱全的菜,前端就像是一个厨师,但手头的厨具,以及品种不够多的食材,但就是要烹饪一道好菜,其实就是个手艺活。废话不多说了,直接上菜谱:
场景一
步骤框:第一步 -> 第二步 -> 第三步
这是一个常见的例子,这是一套流程,我们要做的就是串通整个流程直到结束。这种例子以表单为常见,除了顺序执行,还可提供上一步
按钮,供用户返回上一步重新填写。
使用Vue来设计:
父组件可以是个自定义的 dialog 组件,装着每个流程的页面
<v-dialog>
<step1></step1>
<step2></step2>
<step3></step3>
</v-dialog>
这是一套标准的教科书式写法,哈哈哈,其实我也不介意使用 Vue 的内置 Component:
<template>
<v-dialog>
<keep-alive>
<component :is="conf.component" v-bind="conf.props"
v-on="conf.listeners">
</component>
</keep-alive>
</v-dialog>
</template>
<script>
import stepOne from './step-one'
import stepTwo from './step-two'
import stepThree from './step-three'
const MAP = {
0: stepOne,
1: stepTwo,
2: stepThree
}
export default {
data () {
return {
active: 0 // 0代表第一个页面的索引
}
},
computed: {
conf () {
return {
component: MAP[this.active],
props: { ... },
listeners: { ... }
}
}
}
}
</script>
乍一看页面没有很特别的地方,往往问题会从两个方向去发展:横向扩展和纵向扩展 。
具体点说,如果这个时候产品又要往后再加一个步骤页面呢,但从开发的角度来讲,我们不能仅仅要考虑产品会这一个步骤,可能会加N个步骤(往复杂点想),当然产品如果这么玩的,这个页面的交互还是挺差的。
当然多页面的方式,还是更倾向于使用Vue的内置 component
。
说玩设计,再来说说接口。这种表单设计,无非就是两种操作,新增和编辑。理想情况下,编辑状态时,前端是希望每个页面的数据独立获取,这里暂且不提每个页面之间的依赖关系,但现实往往是后端会把这几个页面的所有数据塞入一个对象中从接口返回。这无非是增加了前端处理的复杂度。
对于这种场景,前端的常规操作有:
这是最常规的处理方式,但如果每个页面都需要传递不同的 props,那父组件会变得非常臃肿。
这个时候我们再从纵向的角度考虑下:
纵向的问题增加了 Event Emits
和 Pass Props
操作的复杂度,对于我们日常维护会有很大的困扰。这个时候或许有些人会提议使用 Vuex,Vuex 确实能够方便我们管理状态,并且每个组件里都能获取到这个状态,只要通过简单的 mapState
即刻获取。但 Vuex 的使用也要根据实际场景,如果仅仅是2个页面的话,使用 Vuex 有的时候恰恰加大了工作量,这很矛盾,我们又要用最简单的方式处理,又要考虑到扩展要不要使用
Vuex,这个时候我还是建议大家多考虑清楚,或者和产品就页面设计的走向了解一个大概。
横向问题 和纵向问题 只是个简单的开始,现在场景要更复杂一点了,页面之间会有依赖。
具体点,就是页面一表单的数据更改会影响到页面二的数据展示,页面二的数据更改会影响到页面三的数据展示。
其实我们也有更好的处理方式,我们需要一个 Controller
。
class Manage {
constructor () {
this.step1 = null
this.step2 = null
this.step3 = null
}
add (step, instance) {
this[step] = instance
}
}
export default new Manage()
页面级:
import manage from './Manage.js'
export default {
name: 'Step1'
...
...
...
created () {
manage.add('step1', this)
}
}
import manage from './Manage.js'
export default {
name: 'Step2'
...
...
...
created () {
manage.add('step2', this)
}
}
这样组件之间的数据共享,可以通过 controller
去处理,获得每个组件的实例并且直接获取数据。
另外,我们还能够向 controller
对象注入一个 store
。
const store = new Vue({
data () {
return { ... }
}
})
class Manage {
constructor () {
this.store = store
}
}
这样组件之间又可以共享一些数据。
写业务之前首先还得多和产品撕下逼,了解产品到底想作甚,刚需,再来考虑交互实现方式,这里不得重新提下软文我只是想在页面上加个链接 。写之前还是得多从宏观上去构建一下,而不是只着眼于细节,毕竟这样也能减少大家重构代码的概率。
………………………………