从手动拼接字符串到前端模板再到react

元程序 2021-07-30 12:23:31

写在前面: 本来这篇文章打算深入写的, 但是春节期间回老家没空调手冷?, 加上水平有限, 很多东西没交代清楚, 所以只发在公众号.

在前端开发的过程中, 我们难免会遇到拼接字符串的情况, 那么为什么需要拼接字符串, 以及怎么更好的处理好这种行为就成了一个可以深入讨论的话题.
首先为什么呢? 当然是为了更好的用户体验以及可能会减轻后端的一些工作量, 平滑的部分刷新当然要比表单提交后整个reload要好很多, 虽然不是spa但咱有这个心啊.
不过怎么样, 从拼接字符串到前端模板再到各种spa框架需要解决的都是客户端渲染的问题. 我们可以做一些对比.

拼接字符串

在jquery一统天下的时代我们首先想到的肯定是$.html, $.append各种操作dom的方法, 当然这样做是可以先实现我们需要的给中效果, 可是在今天spa四处飞的时代, 难免显得有点low了. 这部分其实也没啥好说的, 就是字符串的加加减减, 但是我们需要特别关注一下es6的模板字符串, 如果你现在还在用这个方式, 模板字符串可能会帮上你一点点小忙.

前端模板

那么为了复用以及模块化, 前端模板的出现就理所当然了, 后端的模板我们是滚瓜烂熟, 什么jsp, jade, ejs, jinja2. 等等各种. 如果稍微了解点后端的话我们肯定清楚其实后端也就是将模板编译成字符串发送给客户端, 当然其中各种缓存优化这里不提. 后端能这么做, 那前端呢, 如果在刀耕火种的年代: 前端写好html, js, css扔给后端放到模板里, 当然是不行. 但是这不是nodejs起来以后, 前端加上了各种貌似多此一举的gulp, webpack编译之类, 但是真的是多次一举吗? 未必.  编译的过程放到前端提供了很多可能性, 其中一种就是模板在前端的应用, 说起来这个一点儿都不新鲜, hexo之类的静态网站生成器不就是一个编译过程吗? 输入md生成html, hexo可能做到, 咱webpack更可以了, 当然我们这里不会提到具体的webpack配置, 不然扯的没完了. 前端模板这么一用, 逼格是不是就上来了? 当然这个的劣势也很明显: 配置太麻烦以及如果前后端没有完全分离的话可能会需要后端配置一下. 不过我认为这些都是值得的.

react

其实我对react也没啥深入的研究, 仅仅限于会用, 可能用的还不好(捂脸. 但是作为一个咸鱼我还是勇于丢脸, 这里姑且说一说了.
react我当然可能去说那些特别深的的东西(因为我也不懂.  我们都知道react是基于virtual dom来减少dom操作的, 但是各种语法糖吃的我们很甜. 我们基本上也不需要去了解什么是virtual dom, 以及virtual dom怎么转换成真实的dom. 到这里我们菜真正实现了组件化和模块化, 我们只需要将可能复用的部分拆分成组件就行了, 至于怎么调用, 不是我组件本身需要考虑的, 也就是通用组件基本上不需要拥有自己的状态, 也就是所谓无状态组件.

实例

下面我们以一个购物车为例分别来体会一下三者的区别以及优劣, 不过还不急, 我们先理一下购物车的业务逻辑:

添加删除商品

显示隐藏

其实很简单嘛. 来一点伪代码吧:

$('.product').trigger('add', function (item) {
     var html = `<div>${item.name}</div>`
     $('#cart').append(html).show()
})
$('.product').trigger('add', info)
// 这里省略一点不相关的代码

这么当然是可以的, 反正面条代码往下写总是可以实现业务的, 甚至很多时候很多人都不会想到jquery的这种用法, 往dom节点上不停添加事件, 我们知道事件是长驻内存的, 对性能肯定有一定影响, 而就是没法复用, 难保其他地方有类似的用法. 下面来点业务上的常用做法(前端模板):

var h = require('t')var template = require('test.t')function Cart (el) {  this.products = []  this.cart = $(el)
}
Cart.prototype.add = function (item) {  this.products.push(item)  var html = h.render(template, this.products)  this.cart.html(html).show()
}
Cart.prototype.remove = function (item) {  // 这里需要处理一下才能移除数组里的元素, 不过这里不深究
  this.products.splice(this.products.indexOf(item), 1)  var thml = h.render(template, this.products)  this.cart.html(html)
}
Cart.prototype.show = function () {  return this.cart.show()
}
Cart.prototype.hide = function () {  return this.cart.hide()
}

购物车作为一个类, 当然我们可以用es6改写不过这里没啥影响, 无论是复用还是模块化显然做的比上面的写法要好很多, 对于不能完全使用spa写法的想法, 作为前端我们是可以拿到主动权的, 就算是seo要求再高总能找到发挥的地方.
如果是React呢, 很显然我们需要分割组件:

import React, { Component } from 'react'class Product extends Component {
  render () {}
}class ProductList extends Component {
}class Cart extends Component {
}

具体业务逻辑这里不啰嗦了, 但是可以很明显的感觉到组件分割后, 业务逻辑也清晰了很多