浅析Vue中拆分视图层代码的5点建议


Posted in Javascript onAugust 15, 2019

一.框架的定位

框架通常只是一种设计模式的实现,它并不意味着你可以在开发中避免所有分层设计工作。

SPA 框架几乎都是基于 MVC 或 MVVM 设计模式而建立起来的,这些模式都只是宏观的分层设计,当代码量开始随着项目增大而增多时,问题就会越来越多。许多企业内部的项目仍然在使用 angularjs1.X ,你会发现许多 controller 的体积大到令人发指,稍有经验的团队会利用好 angularjs1 构建的 controller , service , filter 以及路由和消息机制来完成基本的拆分和解耦,这已经能让他们的开发能力中等体量的项目,往往只有掌握了 angularjs1 玩法精髓—— directive 的队伍,才能够在应付大型项目时使代码保持足够的清晰度,当然这只是在代码形态和模块划分上的工作,相当于代码的骨骼,想要让业务逻辑本身更加清晰,就需要更高级的建模设计知识来对业务逻辑进行分层,例如 领域驱动模型 。如果你仍然在使用 angularjs1.x 的版本进行开发,可以参考【如何重构Controller】进行基本的分层拆分设计。

有趣的是一些团队认为无法承载大型项目是 angularjs1.x 的原罪,与他们的开发水平无关,于是将希望寄托于拥有自动化工具加持的现代化 SPA 框架,然而如果有机会观察你就会发现,许多项目对新框架的使用方式和之前并没有本质的差别,只不过是把以前臃肿到不行的代码又换了一种形式塞进了前端工程里,然后借着 ES6 语法和新型框架本身的简洁性,开始沾沾自喜地认为这是自己重构的功劳。

请记住,如果不进行结构设计,即便使用最新版本的最热门的框架,写出来的代码依旧会是一团乱麻。

二. Vue开发中的script拆分优化

以 Vue 框架为例,在工程化工具和 vue-loader 的支撑下,主流的开发模式是基于 *.vue 这种单文件组件形态的。一个典型的 vue 组件包含如下几个部分:

<template>
 <!--视图模板-->
</template>

<script>
 /*编写组件脚本*/
 export default {
 name:'component1'
 }
</script>

<style>
 /*编写组件样式*/
</style>

script 的部分通常包含有 交互逻辑 , 业务逻辑 , 数据转换 以及 DOM操作 ,如果不加整理,很容易变得混乱不堪。 *.vue 文件的本质是View层代码,它应该尽可能轻量并包含与视图有关的信息,即 特性声明 和 事件分发 ,其他的代码理论上都应该剥离出去,这样当项目体量增大后,维护起来就更容易聚焦关键信息,下面就如何进行脚本代码拆分提供一些思路,有一些可能是很基本的原则,为尽可能完整就放在一起,你并不需要从最开始就采纳所有的建议。

1.组件划分

这是View层减重的基础,将可共用的视图组件剥离出去,改为消息机制进行通信,甚至直接剥离出包含视图和业务代码的业务逻辑组件,都可以有效地拆分View层,降低代码的复杂度。

2.剥离业务逻辑代码

script 中最大的一部分一般是业务逻辑,首先将业务逻辑代码剥离为独立的 [name].business.js 模块,这样做的直观好处就是减轻了View层,另一方面是解除了业务逻辑和页面之间的强绑定关系,如果其他页面也涉及到这块业务逻辑中的个别方法,就可以直接进行复用,最后就是当项目逐渐复杂,你决定引入 vuex 来进行状态管理时View层会相对更容易修改。

一段包含基本增删改查逻辑的组件大概是下面的样子:

<script>
 export default{
 name:'XXX',
 methods:{
  handleClickCreate(){},
  handleClickEdit(){},
  handleClickRefresh(){},
  handleClickDelete(){},
  sendCreate(){},
  sendEdit(){},
  sendGetAll(){},
  sendDelete(){}
 }
 }
</script>

简易的剥离方式是将交互逻辑保留在视图层,将业务逻辑部分代码放在另一个模块中,然后利用 ES6 扩展运算符将其加入到组件实例的方法中,如下所示:

<script>
 import OrderBusiness from './Order.business.js';
 export default{
 name:'XXX',
 methods:{
  ...OrderBusiness,
  handleClickCreate(){},
  handleClickEdit(){},
  handleClickRefresh(){},
  handleClickDelete(){},
 }
 }
</script>

这种方式只是一种形态上的模块化拆分,并没有对业务逻辑本身进行梳理。另一种方式是构建独立的业务逻辑服务,保留在View层中的代码很容易转换为使用 vuex 时的编码风格:

<script>
 import OrderBusiness from './Order.business.js';
 export default{
 name:'XXX',
 methods:{
  handleClickCreate(){
  OrderBusiness.sendCreate();
  },
  handleClickEdit(){
  OrderBusiness.sendEdit();
  },
  handleClickRefresh(){
  OrderBusiness.sendGetAll();
  },
  handleClickDelete(){
  OrderBusiness.sendDelete();
  }
 }
 }
</script>

笔者的建议是,前面三个示例随着项目体量的增长可以实现渐进式的修改。

3. 剥离数据转换代码

在前后端分离的开发模式下,前端所需要的数据支持需要从后端请求获得,但请求来的原始数据通常都是无法直接使用的,甚至有可能引发代码报错,例如时间可能是以时间戳形式传过来的,或者你的代码需要取用某个对象属性时,后台同学却在该属性上挂了一个默认值 NULL 等,另一方面,开发过程中的接口改动是无法避免的,所以在代码结构的设计上,应该尽可能将可能变化的部分聚合起来。

比较实用的做法就是为每一个接口建立一个 Transformer 函数,从后台请求来的数据先经过 Transformer 函数变换为前台能够流通使用的数据结构,并在必要的属性上添加适当的默认值防止报错,你可以尽情地在此使用 Lodash.js 等函数工具来加工和重组自己需要的数据,即使最初后台传给你的数据不需要加工,也可以保留一个透传函数或是模块说明以提醒其他协作开发者在面对这种场景时采用类似的做法,它的功能就是 为逻辑层提供直接可用的数据 。当前端代码越来越重时, Transformer 和 Request 部分可以很方便地移动到中间层。

4. 善用computed和filters处理数据展示

对原始数据的转换并不能覆盖所有场景,这就需要在定制展示的场景中利用 computed 和 filters ,它们都可以用来在不改变数据的情况下更改展示结果,例如将数据中的0或1转换为 未完成 和 已完成 ,或者是将时间戳和当前时间作比较后改为可读性更高的 刚刚 , 1分钟前 , 1小时前 , 1天前 等等,这些开发场景中是不能采用强行赋值来处理的,这是就可以使用计算属性 computed 或过滤器 filters 来处理,它们的区别是 computed 一般用于组件内部,不具有通用性,而 filters 一般用于可复用的场景,可以通过下面的形式来定义一个 展示效果为首字母大写 的全局过滤器:

Vue.filter('capitalize', function (value) {
 if (!value) return '';
 value = value.toString();
 return value.charAt(0).toUpperCase() + value.slice(1);
})

当项目中使用 vuex 来进行状态管理时, computed 通常会等价替换为 state 中的 getter 。

5. 使用directive处理DOM操作

尽管 Vue 提供了 refs 这个接口来实现在逻辑层直接操作 DOM ,但我们应当尽可能避免将复杂的 DOM 操作放在这里,有时候页面上 DOM 变化的场景较多,将每个变化都使用数据驱动的方式显然是不合理的,这时就需要用到指令特性 directive ,它常用来补充实现一些业务逻辑无关的 DOM 变化(业务逻辑相关的变化大都通过数据绑定进行了自动关联)。 directive 的基本用法可以直接参考 【官方指南】 ,需要注意的是许多初级开发者都不太在意内存泄漏的问题,在 directive 的使用中需要格外注意这一点,通常我们会在 bind 事件钩子中绑定事件并使用属性持有这个监听函数,并在 unbind 钩子中解除对同一个监听函数的绑定,即使没有使用自定义指令,你也需要建立在必要时解绑监听器的编码习惯:

Vue.directive('clickoutside',{
 bind:function (el, binding){
  //定义监听器
  function handler(e) {
  if (el.contains(e.target)) {
   return false;
  }
  if (binding.expression){
   binding.value(e);
  }
  }
  el.__clickOutSide__ = handler;
  document.addEventListener('click', handler);
 },
 unbind:function (el) {
  document.removeEventListener('click',el.__clickOutSide__);
  delete el.__clickOutSide__ ;
 }
 });

demo 中提供了一个简单的 directive 示例,你可以用它来做练习。

总结

以上所述是小编给大家介绍的Vue中拆分视图层代码的5点建议,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
使Ext的Template可以解析二层的json数据的方法
Dec 22 Javascript
jquery多行滚动/向左或向上滚动/响应鼠标实现思路及代码
Jan 23 Javascript
一段非常简单的js判断浏览器的内核
Aug 17 Javascript
sencha ext js 6 快速入门(必看)
Jun 01 Javascript
HTML5基于Tomcat 7.0实现WebSocket连接并实现简单的实时聊天
Oct 31 Javascript
vue实现简单实时汇率计算功能
Jan 15 Javascript
AngularJS实现的省市二级联动功能示例【可对选项实现增删】
Oct 26 Javascript
vue-cli项目中使用公用的提示弹层tips或加载loading组件实例详解
May 28 Javascript
angular6根据environments配置文件更改开发所需要的环境的方法
Mar 06 Javascript
监听element-ui table滚动事件的方法
Mar 26 Javascript
详解jquery和vue对比
Apr 16 jQuery
node.js中事件触发器events的使用方法实例分析
Nov 23 Javascript
vue的keep-alive用法技巧
Aug 15 #Javascript
Vue开发环境中修改端口号的实现方法
Aug 15 #Javascript
Vue触发隐藏input file的方法实例详解
Aug 14 #Javascript
如何使用50行javaScript代码实现简单版的call,apply,bind
Aug 14 #Javascript
微信小程序之数据绑定原理解析
Aug 14 #Javascript
微信公众号平台接口开发 菜单管理的实现
Aug 14 #Javascript
vue.js中ref和$refs的使用及示例讲解
Aug 14 #Javascript
You might like
杏林同学录(七)
2006/10/09 PHP
php.ini 中文版
2006/10/28 PHP
php使用fputcsv()函数csv文件读写数据的方法
2015/01/06 PHP
详谈phpAdmin修改密码后拒绝访问的问题
2017/04/03 PHP
PHP+redis实现的悲观锁机制示例
2018/06/12 PHP
打豆豆小游戏 用javascript编写的[打豆豆]小游戏
2013/01/08 Javascript
JS 屏蔽按键效果与改变按键效果的示例代码
2013/12/24 Javascript
运用JQuery的toggle实现网页加载完成自动弹窗
2014/03/18 Javascript
jquery向上向下取整适合分页查询
2014/09/06 Javascript
nodejs中的fiber(纤程)库详解
2015/03/24 NodeJs
JavaScript输出当前时间Unix时间戳的方法
2015/04/06 Javascript
jQuery动态效果显示人物结构关系图的方法
2015/05/07 Javascript
AngularJS 在同一个界面启动多个ng-app应用模块详解
2016/12/20 Javascript
详解nodejs微信公众号开发——3.封装消息响应模块
2017/04/10 NodeJs
在Vue 中实现循环渲染多个相同echarts图表
2020/07/20 Javascript
python局域网ip扫描示例分享
2014/04/03 Python
在Docker上开始部署Python应用的教程
2015/04/17 Python
利用Python获取操作系统信息实例
2016/09/02 Python
Python实现的括号匹配判断功能示例
2018/08/25 Python
对python中GUI,Label和Button的实例详解
2019/06/27 Python
python的pygal模块绘制反正切函数图像方法
2019/07/16 Python
Python中的self用法详解
2019/08/06 Python
python删除指定列或多列单个或多个内容实例
2020/06/28 Python
Django实现简单的分页功能
2021/02/22 Python
德国领先的大尺码和超大尺码男装在线零售商:Bigtex
2019/06/22 全球购物
大学毕业通用个人的求职信
2013/12/08 职场文书
幼儿园教师辞职信
2014/01/18 职场文书
中国梦演讲稿教师篇
2014/04/23 职场文书
求职信标题怎么写
2014/05/26 职场文书
理发店策划方案
2014/06/05 职场文书
教师个人读书活动总结
2014/07/08 职场文书
节约每一滴水演讲稿
2014/09/09 职场文书
逃课检讨书怎么写
2015/01/01 职场文书
2015年维修电工工作总结
2015/04/25 职场文书
大学生自我鉴定怎么写
2019/05/07 职场文书
nginx配置虚拟主机的详细步骤
2021/07/21 Servers