资讯专栏INFORMATION COLUMN

React.js 小书 Lesson1-2 - 前端组件化(一):从一个简单的例子讲起

null1145 / 2124人阅读

摘要:一个组件的显示形态和行为有可能是由某些数据决定的。一个简单的点赞功能我们会从一个简单的点赞功能讲起。我们需要结构,准确地来说我们需要这个点赞功能的字符串表示的结构。下一节小书前端组件化二优化操作中我们继续优化这个例子,让它更加通用。

React.js 小书 Lesson1-2 - 前端组件化(一):从一个简单的例子讲起

本文作者:胡子大哈
本文原文:http://huziketang.com/books/react/lesson2

转载请注明出处,保留原文链接以及作者信息

在线阅读:http://huziketang.com/books/react/

React.js 是一个帮助你构建页面 UI 的库。如果你熟悉 MVC 概念的话,那么 React 的组件就相当于 MVC 里面的 View。如果你不熟悉也没关系,你可以简单地理解为,React.js 将帮助我们将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。

一个组件的显示形态和行为有可能是由某些数据决定的。而数据是可能发生改变的,这时候组件的显示形态就会发生相应的改变。而 React.js 也提供了一种非常高效的方式帮助我们做到了数据和组件显示形态之间的同步。

React.js 不是一个框架,它只是一个库。它只提供 UI (view)层面的解决方案。在实际的项目当中,它并不能解决我们所有的问题,需要结合其它的库,例如 Redux、React-router 等来协助提供完整的解决方法。

很多课程一上来就给大家如何配置环境、怎么写 React.js 组件。但是本课程还是希望大家对问题的根源有一个更加深入的了解,其实很多的库、框架都是解决类似的问题。只有我们对这些库、框架解决的问题有深入的了解和思考以后,我们才能得心应手地使用它们,并且有新的框架出来也不会太过迷茫;因为其实它们解决都是同一个问题。

这两节课我们来探讨一下是什么样的问题导致了我们需要前端页面进行组件化,前端页面的组件化需要解决什么样的问题。后续课程我们再来看看 React.js 是怎么解决这些问题的。

所以这几节所讲的内容将和 React.js 的内容没有太大的关系,但是如果你能顺利了解这几节的内容,那么后面哪些对新手来说很复杂的概念对你来说就是非常自然的事。

一个简单的点赞功能

我们会从一个简单的点赞功能讲起。 假设现在我们需要实现一个点赞、取消点赞的功能。

如果你对前端稍微有一点了解,你就顺手拈来:

HTML:

  
    

为了模拟现实当中的实际情况,所以这里特意把这个 button 里面的 HTML 结构搞得稍微复杂一些。有了这个 HTML 结构,现在就给它加入一些 JavaScript 的行为:

JavaScript:

  const button = document.querySelector(".like-btn")
  const buttonText = button.querySelector(".like-text")
  let isLiked = false
  button.addEventListener("click", () => {
    isLiked = !isLiked
    if (isLiked) {
      buttonText.innerHTML = "取消"
    } else {
      buttonText.innerHTML = "点赞"
    }
  }, false)

功能和实现都很简单,按钮已经可以提供点赞和取消点赞的功能。这时候你的同事跑过来了,说他很喜欢你的按钮,他也想用你写的这个点赞功能。这时候问题就来了,你就会发现这种实现方式很致命:你的同事要把整个 button 和里面的结构复制过去,还有整段 JavaScript 代码也要复制过去。这样的实现方式没有任何可复用性。

结构复用

现在我们来重新编写这个点赞功能,让它具备一定的可复用。这次我们先写一个类,这个类有 render 方法,这个方法里面直接返回一个表示 HTML 结构的字符串:

  class LikeButton {
    render () {
      return `
        
      `
    }
  }

然后可以用这个类来构建不同的点赞功能的实例,然后把它们插到页面中。

  const wrapper = document.querySelector(".wrapper")
  const likeButton1 = new LikeButton()
  wrapper.innerHTML = likeButton1.render()
  
  const likeButton2 = new LikeButton()
  wrapper.innerHTML += likeButton2.render()

这里非常暴力地使用了 innerHTML ,把两个按钮粗鲁地插入了 wrapper 当中。虽然你可能会对这种实现方式非常不满意,但我们还是勉强了实现了结构的复用。我们后面再来优化它。

实现简单的组件化

你一定会发现,现在的按钮是死的,你点击它它根本不会有什么反应。因为根本没有往上面添加事件。但是问题来了,LikeButton 类里面是虽然说有一个 button,但是这玩意根本就是在字符串里面的。你怎么能往一个字符串里面添加事件呢?DOM 事件的 API 只有 DOM 结构才能用。

我们需要 DOM 结构,准确地来说:我们需要这个点赞功能的 HTML 字符串表示的 DOM 结构。假设我们现在有一个函数 createDOMFromString ,你往这个函数传入 HTML 字符串,但是它会把相应的 DOM 元素返回给你。这个问题就可以额解决了。

// ::String => ::Document
const createDOMFromString = (domString) => {
  // TODO 
}

先不用管这个函数应该怎么实现,先知道它是干嘛的。拿来用就好,这时候用它来改写一下 LikeButton 类:

  class LikeButton {
    render () {
      this.el = createDOMFromString(`
        
      `)
      this.el.addEventListener("click", () => console.log("click"), false)
      return this.el
    }
  }

现在 render() 返回的不是一个 html 字符串了,而是一个由这个 html 字符串所生成的 DOM。在返回 DOM 元素之前会先给这个 DOM 元素上添加事件再返回。

因为现在 render 返回的是 DOM 元素,所以不能用 innerHTML 暴力地插入 wrapper。而是要用 DOM API 插进去。

  const wrapper = document.querySelector(".wrapper")

  const likeButton1 = new LikeButton()
  wrapper.appendChild(likeButton1.render())

  const likeButton2 = new LikeButton()
  wrapper.appendChild(likeButton2.render())

现在你点击这两个按钮,每个按钮都会在控制台打印 click,说明事件绑定成功了。但是按钮上的文本还是没有发生改变,只要稍微改动一下 LikeButton 的代码就可以完成完整的功能:

  class LikeButton {
    constructor () {
      this.state = { isLiked: false }
    }

    changeLikeText () {
      const likeText = this.el.querySelector(".like-text")
      this.state.isLiked = !this.state.isLiked
      likeText.innerHTML = this.state.isLiked ? "取消" : "点赞"
    }

    render () {
      this.el = createDOMFromString(`
        
      `)
      this.el.addEventListener("click", this.changeLikeText.bind(this), false)
      return this.el
    }
  }

这里的代码稍微长了一些,但是还是很好理解。只不过是在给 LikeButton 类添加了构造函数,这个构造函数会给每一个 LikeButton 的实例添加一个对象 statestate 里面保存了每个按钮自己是否点赞的状态。还改写了原来的事件绑定函数:原来只打印 click,现在点击的按钮的时候会调用 changeLikeText 方法,这个方法会根据 this.state 的状态改变点赞按钮的文本。

现在这个组件的可复用性已经很不错了,你的同事们只要实例化一下然后插入到 DOM 里面去就好了。

下一节《React.js 小书 Lesson3 - 前端组件化(二):优化 DOM 操作》中我们继续优化这个例子,让它更加通用。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89655.html

相关文章

  • 本关于 React.js 小书

    摘要:因为工作中一直在使用,也一直以来想总结一下自己关于的一些知识经验。于是把一些想法慢慢整理书写下来,做成一本开源免费专业简单的入门级别的小书,提供给社区。本书的后续可能会做成视频版本,敬请期待。本作品采用署名禁止演绎国际许可协议进行许可 React.js 小书 本文作者:胡子大哈本文原文:React.js 小书 转载请注明出处,保留原文链接以及作者信息 在线阅读:http://huzi...

    Scorpion 评论0 收藏0
  • React.js 小书 Lesson3 - 前端件化(二):优化 DOM 操作

    摘要:一个组件的显示形态由多个状态决定的情况非常常见。我们顺利地消除了手动的操作。非一般的暴力,因为每次都重新构造新增删除元素,会导致浏览器进行大量的重排,严重影响性能。下一节小书前端组件化三抽象出公共组件类我们把这个通用模式抽离到一个类当中。 React.js 小书 Lesson3 - 前端组件化(二):优化 DOM 操作 本文作者:胡子大哈本文原文:http://huziketang....

    Drinkey 评论0 收藏0
  • 2017-09-07 前端日报

    摘要:前端日报精选机制详解与中实践应用基础与实践如何用获取虚拟键盘高度适用所有平台和入门教程阮一峰的网络日志编程技能提升指南中文到底什么是又是什么众成翻译调用模块腾讯前端团队社区小书从一个简单的例子讲起小书教程小书优化操作小书教 2017-09-07 前端日报 精选 JavaScript Event Loop 机制详解与 Vue.js 中实践应用 Redux 基础与实践如何用 js 获取虚拟...

    沈俭 评论0 收藏0
  • React.js 小书 Lesson17 - 前端应用状态管理 —— 状态提升

    摘要:在实际项目当中状态提升并不是一个好的解决方案,所以我们后续会引入这样的状态管理工具来帮助我们来管理这种共享状态,但是在讲解到之前,我们暂时采取状态提升的方式来进行管理。 React.js 小书 Lesson17 - 前端应用状态管理 —— 状态提升 本文作者:胡子大哈本文原文:http://huziketang.com/books/react/lesson17 转载请注明出处,保留原...

    newtrek 评论0 收藏0
  • React.js 小书 Lesson4 - 前端件化(三):抽象出公共组件

    摘要:最后抽离出来了一个类,可以帮助我们更好的做组件化。一个组件有自己的显示形态上面的结构和内容行为,组件的显示形态和行为可以由数据状态和配置参数共同决定。接下来我们开始正式进入主题,开始正式介绍。下一节链接直达小书基本环境安装 React.js 小书 Lesson4 - 前端组件化(三):抽象出公共组件类 本文作者:胡子大哈本文原文:http://huziketang.com/books...

    jsbintask 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<