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

一.框架的定位

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

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点建议,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • 详解Vuex下Store的模块化拆分实践

    前言 最近的项目用到了 vue.js + vuex + vue-router 全家桶,版本为 >2.0,在搞Store的时候发现,圈子里大部分关于vuex的文章都是比较基础的Demo搭建方式,很少有涉及到比较复杂的模块化拆分的Store实践,而且事实上也有朋友在实践中问到过这方面的内容,vuex自身提供了模块化的方式,因此在这里总结一下我自己在项目里的心得. 模块化拆分 vue.js的项目文件结构在这里就不说了,大家可以通过vue-cli初始化项目,脚手架会为你搭建一个start项目的最佳实践.

  • vue实现todolist功能、todolist组件拆分及todolist的删除功能

    •简单todolist功能的实现 用户点击提交按钮时,将input框的内容显示在下方的list中,同时清空list中内容. <body> <div id="root"> <div> <input v-model="inputValue"/> <button @click="submit">submit</button> </div> <ul> <

  • 详解vuex之store拆分即多模块状态管理(modules)篇

    了解vuex的朋友都知道它是vue用来集中管理状态的容器,如果了解过Reduce的朋友可能看见他时就会非常熟悉,都是用来管理全局的状态的,实现不同组件之间相互的数据访问.这里我们不介绍vuex,主要介绍vuex拆分store以及多模块管理.我们知道如果一个项目非常大的话状态就会非常的多,如果不进行分类处理,所有的状态都维护在一个state里面的话,状态管理就会变得非常的混乱,这样非常不利于项目的后期维护.我们现在前端推崇模块化开发,为的就是提高开发效率和维护效率,避免重复工作.那么vuex是怎么

  • 详解Vue.js项目API、Router配置拆分实践

    前后端分离开发方式前端拥有更高的控制权 随着前端框架技术的飞速发展,Router这个概念也被迅速普及到前端项目中,在早期前后的没有分离的时期下,并没有明确的路由概念,前端页面跳转大多是通过后端进行请求转发的,比如在Spring MVC项目中,进行一个页面跳转如下(画红线部分): 前端需要一个超链接,链接的href=/manager,这样这个超链接被转发到scs/waitFollowed路径指定的页面. 前后的分离后,前端页面跳转的方式发生了变化,不再需要后端处理了,数据交换方式也改变了,由此前端

  • 详解vue移动端项目代码拆分记录

    撸一套vue多端共用,非常适合需要快速且全面上线的项目.但是多端共用一套vue代码,由于平台间的互相限制,每端在某些业务例如支付分享等是完全独立的代码,每个平台的支付方式也会有所差异,造成在这些业务的实现过程中会有太冗余的"if else"判断.所以为了提高代码的复用性.扩展性,可以将代码拆分,以-小程序和App两端举例,一份部署到小程序,一份部署到App(Android&Ios). 首先代码拆分应该保证本地开发的时候只有一套代码,提取所有公共页面,并且分别提取小程序和app的

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

    一.框架的定位 框架通常只是一种设计模式的实现,它并不意味着你可以在开发中避免所有分层设计工作. SPA 框架几乎都是基于 MVC 或 MVVM 设计模式而建立起来的,这些模式都只是宏观的分层设计,当代码量开始随着项目增大而增多时,问题就会越来越多.许多企业内部的项目仍然在使用 angularjs1.X ,你会发现许多 controller 的体积大到令人发指,稍有经验的团队会利用好 angularjs1 构建的 controller , service , filter 以及路由和消息机制来完

  • VUE中的无限循环代码解析

    代码如下所示: <template> <div id=""> <ul v-for="(item,index) in listaaa"> <li v-if='dealFun(item.cdate,index)'>{{item.cdate}}</li> </ul> </div> </template> <script> export default { name:

  • 浅析Vue 中的 render 函数

    render函数是什么 简单的说,在vue中我们使用模板HTML语法组建页面的,使用render函数我们可以用js语言来构建DOM 因为vue是虚拟DOM,所以在拿到template模板时也要转译成VNode的函数,而用render函数构建DOM,vue就免去了转译的过程. 当使用render函数描述虚拟DOM时,vue提供一个函数,这个函数是就构建虚拟DOM所需要的工具.官网上给他起了个名字叫createElement.还有约定的简写叫h, vm中有一个方法_c,也是这个函数的别名 先看官网对

  • 浅析vue中的nextTick

    背景 vue是异步渲染的,当data改变之后,DOM不会立刻被渲染,页面渲染时会将data的修改做整合,多次data修改只会做整合最后一次性渲染出来,这也是异步渲染的原因.只有异步渲染才可以实现整合操作. 例子 methods: { update() { for (let i = 0; i < 10; i++) { this.testNum = this.testNum + i; } }, }, 在你的 Vue 视图中, testNum 会发生变化.不过需要注意的是这个变化的过程,虽然我们把 f

  • 浅析vue中的组件传值

    目录 一.正向传值 验证写法 props验证 更多验证 二.逆向传值 自定义事件 实现逆向传值 三.同胞传值/兄弟传值 low的方式(了解) 中央事件总线 eventBus 前言: 只要是做项目,组件和组件之间的传值是不可避免的,那么怎样才能完成组件之间的传值呢?我总结了以下几点,若有不足,欢迎补充 一.正向传值 基本写法: props:[“接收变量1”,“接收变量2”.......] 使用: 1,在需要接收数据的子组件中,定义props设置接收变量 <template> <div>

  • vue中拆分组件的实战案例

    目录 一.组件化诞生的历史 二.为什么业务组件越开发越难维护 人的问题 技术问题 2.1 项目现状 2.2 理想目标 三.举一个实际的例子 3.1 需求背景 3.2 开发之前: 前端设计文档 数据流向图 目录结构 逻辑控制 拆分的原则 3.3 受控组件和非受控组件 3.4 开发进行: 逻辑变量和UI变量 四.持续的优化 五.可能的问题 五.实践是学习前端的捷径 总结 组件化是一种思维的表现,这种技能映射到人的本质是,一个人是否有能力把一个复杂的问题拆解.简单化的能力. 一.组件化诞生的历史 我们

  • 浅析Vue中Virtual DOM和Diff原理及实现

    目录 0. 写在开头 1. vdom 2. Diff 0. 写在开头 本文将秉承Talk is cheap, show me the code原则,做到文字最精简,一切交由代码说明! 1. vdom vdom即虚拟DOM,将DOM映射为JS对象,结合diff算法更新DOM 以下为DOM <div id="app"> <div class="home">home</div> </div> 映射成VDOM { tag: '

  • vue 中的keep-alive实例代码

    Vue 实现组件信息的缓存 当我们在开发vue的项目过程中,避免不了在路由切换到其他的component再返回后该组件数据会重新加载,处理这种情况我们就需要用到keep-alive来缓存vue的组件信息,使其不再重新加载. 一.在app.vue里 <keep-alive> <router-view></router-view> </keep-alive> 但是这种情况会对所有的组件进行缓存,不能达到单个组件缓存的效果. 那么我们给部分组件加上,实现方法如下:

  • vue中的过滤器实例代码详解

    过滤器 1.过滤器规则 Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化.过滤器可以用在两个地方: 双花括号插值{{}}和  v-bind 表达式 (后者从 2.1.0+ 开始支持).过滤器应该被添加在 JavaScript 表达式的尾部,由"管道"符号指示: <!-- 在双花括号中 --> {{ name | Upper }} <!-- 在 `v-bind` 中 --> <div v-bind:id="martin | Upper

  • vue 中 命名视图的用法实例详解

    今天主要记录  vue中命名视图的用法 先奉上官网网址:https://router.vuejs.org/zh/guide/essentials/named-views.html 一般情况下,一个页面里面可能有多个组件,比如侧边栏,内容区,侧边栏是一个组件.内容区是一个组件,我们普遍会将两个组件作为子组件添加到主页面中,因为页面中只有一个 router-view视图,那么问题来了,怎么让一个页面中有多个视图呢,拥有多个视图,很随意,多写几个router-view标签就行了,但是每个router-

随机推荐