从jQuery到Vue

前言

目前公司主站以及老的KMS页面采用的是JQ + ES6, 而新版KMS则是由Vue开发的。

使用Vue开发更加高效,优雅。但是从JQuery转到Vue其实有个过程,我在开发前自认为对Vue还是挺了解的,但是真正动手起来发现还是有一些不适应。因此在此写下一些心得,记录下来。

思维方式差异

JQuery

对于JQ大家肯定都非常熟悉,使用JQ开发,就像把大象装进冰箱:

  1. 拿到DOM元素

  2. 封装功能函数

  3. 操作DOM

这种思维很直观,拿到元素,然后就可以"为所欲为"。但是在页面复杂程度越来越高的情况,许多代码无法复用,代码维护成本高,缺少规范。

JQ组件化

在业务功能,业务场景越变越多的情况下,为了提高开发效率,前端组件化势在必行。于是
前端组件化规范就出现了。基本思想是通过继承来将代码有效组织起来,减少一些重复的劳动,规范了组件的生命周期。

优点:

  1. 将原来分散的组件有机结合起来,有利于以后业务的扩展

  2. 提供了完善的继承模式,很容易产出新业务的组件

  3. 提供了事件机制以及全局标识符

缺点:

  1. 过多的继承使得组件的依赖越来越多,但是不引入依赖组件又无法使用

  2. 缺少css样式支持

  3. 本质上还是函数的封装,并没有从视图层面上进行组件的划分,更接近于js模块化开发

vue有v-model连接数据和视图,而react则通过管理state来重新渲染视图。

JQuery没有中间的过渡层,我们需要花费很大的精力来解决它们之间相互的联系。直接操作DOM时很难写出高效而又优雅的代码,从而使得前端代码满满变得越来越难以维护

JQuery与现代框架

Vue

Vue 最显著的特性之一便是不太引人注意的响应式系统(reactivity system)

在开发Vue的时候,并不需要取DOM元素,这个让我别扭了一会,因为我还没有将思维改变过来。总的来说,写vue的过程分为三步:

  1. V-视图层(包括HTML,vue指令,其他vue组件等等)

  2. M-数据层 (包括从后端拿到的数据以及自己定义的数据)

  3. v-model (vue实例)

视图层和数据层其实是没有联系的,所以Vue的核心就在v-model上面,该实例会代理其data属性,并且将视图层和model层联系起来。至此,我们无需再关心视图层面,只需要关心数据的变化即可,因为数据的变化会反应到视图上。模板语法

Vue组件化

在vue中,一个组件其实就是一个vue实例,而其中的单文件组件,更是一个强大的功能,配合webpack和vue-loader,可以解析后缀名为vue的文件。格式大概如下


<template>
    html, vue指令, pug...
</template>

<script>
 import ...  from 'path/to/your-file'
 export default {
     data () {
         return {
             isLogin:false,
         }
     },
     methods: {

     },
     watch: {

     },
     computed: {

     },
     created: {

     }
     ...
 }
</script>

<style lang='scss' scoped>
    css,scss...
</style>

单文件组件

优点:

  1. 组件既拥有自己的状态,样式,行为,也可以通过在组件外传的props来改变自身状态,复用性和扩展性强

  2. 完善的模板语法,事件绑定机制以及生命周期,开发效率提升一个层次

  3. 响应式设计,改变数据的同时,视图跟着改变,不需要再去手动操作DOM。

缺点:

  1. 使用webpack等打包工具才能发挥最大威力
组件通信

一个页面由许多个组件构成,组件之间可以嵌套,每个组件都有自身的状态,但是有时候需要一个组件的变化反映到另一个组件上,这个时候就需要组件之间的通信了。

组件通信

  1. 每个组件都有自己内部的状态,不要从外部直接改变组件内部的状态,例如

  2. 子组件通过props接收父组件的数据,父组件通过控制props来改变子组件的状态。

  3. 子组件通过事件来与父组件通信,在子组件内部触发该vue实例(组件)的事件,然后在父组件上监听该事件即可。 vue自定义事件

开始使用Vue吧

设计数据结构

数据的变化会更新DOM,这是Vue迷人的一点,因此好的数据结构非常重要,在写Vue组件之前,不妨按照一下思路来思考一下:

  1. 组件内部,必要的数据有哪些,能否表示组件的内部状态

  2. 组件接收外部的数据有哪些,能否从外部使组件发生预期的变化

  3. 数据精简化,检查是否有冗余的数据

俗话说:磨刀不误砍柴工,设计好数据结构对之后的开发很有益。

计算属性

数据大部分都声明在Vue实例的data的属性中(在组件中data必须是函数,返回一个对象),当时当数据有着逻辑计算时,直接从data中拿数据然后用表达式并不是个好方法。


<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

上面的代码,在模板内放入了过多的逻辑,对于复杂的逻辑运算应当使用计算属性


data: {
    return {
        message: 'Hello,World'
    }
},
computed: {
    reversedMessage() {
        return this.message.split('').reverse().join('')
    }
}

计算属性可以当作数据结构的一种,任何复杂的数据运算都声明在计算属性中。
至于为什么不用methods,这里有回答计算属性 VS methods

构建视图层

设计好数据结构之后,书写视图层显得得心应手,但是前提是了解Vue的模板语法模板语法

我在开发过程中遇到一些坑,都是小问题,但是也不能忽视:

  1. 在html上绑定属性,一律使用v-bind语法,否则会解析为字符串。

  2. 不要在子组件中改变props,特别是引用类型,如果有需要请使用计算属性来处理数据。

构建高性能组件

利用slot混合组件

在组件嵌套的时候,为了能更灵活的使用组件,使用slot来混合组件的内容是一种非常好的方式

现在构建一个有头部和尾部的组件,但是中间的内容由使用组件的人来决定(父组件作用域中)。

子组件child


<div>
    <div id="header"></div>
    <slot slot="body"></slot>
    <div id="footer"></div>
</div>

父组件


<div>
    <child>
        <p slot="body">这是一个段落</p>
    </child>
</div>

父组件中的内容会插入到对应的slot中。最后渲染为


<div>
    <div id="header"></div>
    <p>这是一个段落</p>
    <div id="footer"></div>
</div>

当混合组件时,会碰到从子组件取值的情况。当时组件之间作用域是孤立的,之前的组件通信的方式也不适用于混合组件的情况,因此作用域插槽出现了作用域插槽

通过作用域插槽可以将子组件中的数据通过插槽传到父组件中,然后父组件通过scope取到数据,根据数据插入需要的模板。

编写可复用的组件

Vue组件的API主要三部分

  • Props 允许外部环境传递数据给组件

  • Events 允许从外部环境在组件内触发副作用

  • Slots 允许外部环境将额外的内容组合在组件中。

基础架构优化

  • html模板要简介明了,不适合放入过多逻辑操作,需要运算的时候使用computed

  • 构建中大型项目,组件尽量拆分细化,一个组件做好一件事情

  • Vue是单向数据流,使用vuex等工具来管理组件状态,是一个好的选择

以上是我的一些小总结,文章以后随着知识的增长也会反复更新,有误之处欢迎指正。

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。