怎样在不使用框架的基础上开发一个 Javascript 组件

本文讲的是怎样在不使用框架的基础上开发一个 Javascript 组件,


许多开发者(包括我)犯的一个错误是当遇到问题时他们总是自上而下地考虑问题。他们想问题的时候,总是从考虑框架(Framework),插件(Plugin),预处理器(Pre-processors),后处理器(Post-processors),面向对象模式(objected-oriented patterns)等等这些方面出发,他们也可能会从他们以前看过的一篇文章来考虑。而这时如果有一个生成器(Generator)的话,他们当然也愿意使用生成器提供的脚手架(Scaffold)来解决这样的问题。但是随着使用所有这些优秀的工具和强大的插件,我们往往忽略了,我们到底要构建什么,以及我们为什么要构建。在大多数场景下,我们实际上并不需要任何 的这些框架!我们在 没有 使用任何 JavaScript 框架和工具的情况下构建了一个简单组件实例。这篇文章给想给那些中高级程序员提个醒,其实不用框架和膨胀软件(Bloatware)也可以做事。当然,这里的经验和代码示例对初级工程师们来说也是易懂和实用的。

我们要建立一个公司员工列表(通常我说的是一个最近推文或某事的列表但他们现在需要你建立一个应用访问他们的 API,挺复杂的)。我们的产品经理想要在公司网站首页上放上最近员工的列表,并且要做到自动更新。这个列表要包括新员工的照片,名字,所在城市等信息。没什么夸张的,对吧?那么,在目前情况下,比方说公司首页是和其他代码库是分开的,而且它已经用 jQuery 做了几个动画效果。那么,这是我们的假设:

  • 一个半自动更新列表
  • 单页面
  • 你是这个项目唯一的开发者
  • 时间和资源都是无限的
  • 这个页面上已经用了 jQuery

所以你从何处下手呢?你是否立即要用 Angular ?因为你知道你不花时间使用一个 $scope.employees 和 ng-repeat 。你是否要用 React ?因为它在列表中插入员工标签 很快 。亦或是切换到静态网页然后使用 Webpack?然后你就能用 Jade 写 HTML 用Sass 写 CSS ?因为说实话谁还会看原始的标签。不想骗你,最后一个对我 真的 很有吸引力。但是我们真的需要它吗?正确的答案是 'no' 。这些东西并不能切实解决我们手上的问题。而且他们让软件栈方面变得更加令人困惑。想想如果下次另一个工程师,特别是初级工程师来接手这个项目;当另一个工程师只是做较小修改时,你并不想要他被这些花哨功能所困惑。所以,我们简单组件的代码是什么样的呢?

<ul class="employee-list js-employee-list"></ul>

就是它。这就是我们所有开始的地方。你可能注意到我给这个 div 添加的第二个类是以 js- 开始的。如果你不熟悉这种模式的话,这样做是因为我想向以后的开发者表明这个组件与 JavaScript 关联。这种方式我们就能够区分 只是 为 JS 做交互的类和 只是和 CSS 绑定的类。它能让重构更容易。现在,让我们最后让这个列表变得美观 一点 。(读者注意:我可能是世界上最糟的设计师)。我更喜欢使用像一种 BEM 和 SMACSS 的 CSS 结构,但是为了这个例子更简洁,这些名称和结构就先这样保留吧:

* { box-sizing: border-box; }

.employee-list {
  background: lavender;
  padding: 2rem 0.5rem;
  border: 1px solid royalblue;
  border-radius: 0.5rem;
  max-width: 320px;
}

那么现在我给列表添加一些样式,虽然还没完成,但这是个过程。现在,增加一个示例员工:

<ul class="employee-list js-employee-list">
  <li class="employee">
    <!--   占位图服务真是很好用   -->
    <img src="http://placebeyonce.com/100-100" alt="Photo of Beyoncé" class="employee-photo">
    <div class="employee-name">Beyoncé Knowles</div>
    <div class="employee-location">Santa Monica, CA</div>
  </li>
</ul>  

.employee {
  list-style: none;
}

.employee + .employee {
  padding-top: 0.5rem;
}

.employee:after {
  content: ' ';
  height: 0;
  display: block;
  clear: both;
}

.employee-photo {
  float: left;
  padding: 0 0.5rem 0.5rem 0;
}

棒极了!所以现在我们有一个拥有简单样式和布局的一个员工列表。那么,接下来是什么?员工的数量应该可能不只有一个。我们需要自动获取他们。我们来获取员工数据:

// 用一个 IIFE 包裹代码,从而使它们与其他代码隔离开。
(() => {
  // 严格模式用来防止错误和确保 ES6 特性可用
  'use strict'

  // 我们使用 jQuery 的 ajax 方法确保代码简洁
  // 从 randomuser.me 拉取数据 作为我们 'employee API' 的数据源
  // (记住这是一个假的推文列表(a fake tweet list))
  $.ajax({
    url: 'https://randomuser.me/api/',
    dataType: 'json',
    success: (data) => {
      // 成功!我们得到数据!
      alert(JSON.stringify(data))
    }
  })
})()

很棒!我们获得了员工数据,其间没有依靠框架和复杂的预处理器,也没有花两小时争论要选用哪个脚手架工具。目前我们使用 alert 函数 来替代测试框架以确保数据符合我们的预期。现在,我们需要通过一些模版解析数据去插入到 .employee-list 中。所以 完成之后然后来制作模版:

$.ajax({
  url: 'https://randomuser.me/api/',
  // query string parameters to append
  data: {
    results: 3
  },
  dataType: 'json',
  success: (data) => {
      // 成功!我们获得数据!
    let employee = `<li class="employee">
        <img src="${data.results[0].picture.thumbnail}" alt="Photo of ${data.results[0].name.first}" class="employee-photo">
        <div class="employee-name">${data.results[0].name.first} ${data.results[0].name.last}</div>
        <div class="employee-location">${data.results[0].location.city}, ${data.results[0].location.state}</div>
      </li>`
      $('.js-employee-list').append(employee)
    }
  })

好极了!现在我们有了一个获取用户的脚本,把用户插入模版中,然后将模版呈现在页面上。虽然有点马虎而且只能处理一个用户。现在到重构的时间了:

// 把员工信息转换成一块标签
function employee_markup (employee) {
  return `<li class="employee">
    <img src="${employee.picture.thumbnail}" alt="Photo of ${employee.name.first}" class="employee-photo">
    <div class="employee-name">${employee.name.first} ${employee.name.last}</div>
    <div class="employee-location">${employee.location.city}, ${employee.location.state}</div>
  </li>`
}

$.ajax({
  url: 'https://randomuser.me/api/',
  dataType: 'json',
  // 查询字符串参数
  data: {
    results: 3
  },
  success: (data) => {
    // 成功! 我们获得了数据
    let employees_markup = ''
    data.results.forEach((employee) => {
      employees_markup += employee_markup(employee)
    })
    $('.js-employee-list').append(employees_markup)
  }
})

现在你得到了!一个没有使用框架和任何构建流程的功能完备的小 JavaScript 组件。包含注释在内它只有 66 行代码并且完全可以扩展添加一个动画,连接,分析,之类的功能。查看以下完成的组件:

<iframe height='266' scrolling='no' src='//codepen.io/jacopotarantino/embed/MyGVOv/?height=266&theme-id=0&default-tab=js,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen MyGVOv by jacopotarantino (@jacopotarantino) on CodePen. </iframe>

源代码 MyGVOv 作者: jacopotarantino (@jacopotarantino) 在 CodePen.

现在,显然这只是一个非常非常简单的组件而且可能不能满足你特定项目的所有需求。如果你保持简单的想法,你能坚持无框架这个原则做到更多。或者,如果你的需求很多但复杂度较低,可以考虑像 Webpack 这样的构建工具。构建工具(在这个主题上)并不完全像 框架和插件它们那样完成事情。构建工具并不会在最后服务用户的代码中添加臃肿的东西,它只存在于你的工具箱中。因为我们的目标是从框架中剥离并为我们的使用者创造更好体验,和对自己来说则是创造更好管理的代码。Webpack 能处理大量繁杂的事务从而让你专注于更有意思的事。我在我的 UI Component Generator 用了它,其中还引入了非常小的框架和工具可以让你去写没有冗余的大量功能代码。当你不用 JavaScript 框架,事情可能很快变得"原始"而且代码可能变得令人困惑。所以,当你做这些组件时,要考虑一种代码结构并且坚持它。一致性是确保代码优雅的关键。

记住,最重要的是你一定要测试和给你代码编写文档。 “不写代码文档,等于没写” - @mirisuzanne

彩蛋

我做了一次标题党,而我使用了 jQuery。这只是为了简洁起见,我并不赞成使用 jQuery,你并不需要它。对于这些好奇,其实可以利用下面的原生代码来重写那些超级易懂的代码。

原生 JavaScript 的 AJAX 请求

不幸地这个代码没有任何简化,但你可以自己用相对少的代码来实现。

(() => {
  'use strict'

  // 创建一个新的 XMLHttpRequest。这是在无框架情况下使用 AJAX 的方法
  const xhr = new XMLHttpRequest()
  // 声明 HTTP 请求方法和地址
  xhr.open('GET', 'https://randomuser.me/api/?results=3')
  // in a GET request what you send doesn't matter GET 请求
  // in a POST request this is the request body
  xhr.send(null)

  // 等待 'readystatechange' 状态改变去触发 xhr 对象
  xhr.onreadystatechange = function () {
    //等待 xhr 成功成功返回
    if (xhr.readyState !== 4 ) { return }
    // 非 200 状态时输出错误信息
    if (xhr.status !== 200) { return console.log('Error: ' + xhr.status) }

    // 一切正常!输出响应
    console.log(xhr.responseText)
  }
})()

用原生 JavaScript 进行 DOM 插入

现在浏览器们基本接受了 jQuery 的选择器,这个超级简单。

(() => {
  'use strict'

  const employee_list = document.querySelector('.js-employee-list')
  const employees_markup = `
    <li class="employee"></li>
    <li class="employee"></li>
    <li class="employee"></li>
  `
  employee_list.innerHTML = employees_markup
})()

就这么简单!

没有采用 ES6 特性

除非是的你工作需要,否则我真的不推荐回退到 ES5,下面这些是 ES6 可以代替的。

字符串插值

用 Photo of ${employee}. 替换所有的 'Photo of ' + employee + '.'

let 和 const

这个例子中的 var 关键字都可以用 let 和 const 关键字替代,但你自己代码你要当心。

箭头函数

用 (employee) => { 替换 function (employee) { 。 再提醒一次,这个例子中代码可以被替代,但是你自己的代码你要当心。let, const,和箭头函数和 var 和 function 的作用域不同,并且如果你的代码马虎,没有结构化,在它们之间切换可能会破坏你的代码。





原文发布时间为:2016年05月11日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2024-10-03 08:07:03

怎样在不使用框架的基础上开发一个 Javascript 组件的相关文章

有没有办法在不改变web程序源代码的基础上加入一个自己的过滤器?

问题描述 有没有办法在不改变web程序源代码的基础上加入一个自己的过滤器?大致需求是这样的,比如其他厂商做了个WEB程序,我想让这个WEB程序运行的时候,比如用户登录的时候能被我的过滤器给审计到.原来想通过改写它的web.xml,然后加上个自己写的过滤器.但是觉得这样不太好,有没有办法不改变它的web.xml来做到呢?如果可以请说明大致的思路:采用什么原理?大致要做的东西?我的邮箱lifeneedyou@163.com,MSN也是这 问题补充: 有没有办法在不改变web程序源代码的基础上加入一个

程序-基于单片机430g2553基础上做一个万用表

问题描述 基于单片机430g2553基础上做一个万用表 基于单片机430g2553基础上做一个电压表,直流电压量程:200mV.2V.20V , 精度(1%+1)内,交流电压量程:200mV.2V.20V,精度(1%+1)内,频率响应40~400Hz,5110数码显示,要求用一节9V电池供电,电阻测量:1Ω---1MΩ,精度(5%+1)内,,用的是adg804,程序怎么写 解决方案 http://wenku.baidu.com/view/b4c31c5d312b3169a451a412.html

中国将在 Sailfish 基础上开发移动操作系统

在授权印度和俄罗斯之后,中国也将在 Sailfish 基础上研发本国的移动操作系统. Sailfish 是芬兰公司 Jolla 在 MeeGo 基础上开发的移动操作系统,俄罗斯等国青睐 Sailfish 的原因是不想过度依赖美国的操作系统和平台 (aka Android 和 iOS).中国青睐 Sailfish 的原因估计类似,中国 Sailfish 财团从 Jolla 获得了独家授权开发中国版本的 Sailfish. 财团的一位主要投资者 Shan Li 称,中国需要自己的独立移动操作系统,他

在Livemedia的基础上开发自己的流媒体客户端

一.背景 二.Livemedia框架介绍 1.总体框架 2.客户端框架 2.1 客户端openRTSP流程 2.2增加一种新的媒体 2.2.1增加媒体的format 2.2.2 新媒体需要考虑的问题 2.3类详细说明 2.3.1 BasicUsageEnvironment, UsageEnvironment 2.3.2 groupsock 2.3.3 livemedia 三.一些总结 A. Buffer 管理 B. How to control the receive loop C. PAUSE

HighCharts 框架我想在Tooltip默认显示的基础上添加一个来自后台的一个说明字段

问题描述 这个字段只有在这个位置出现,和其他数据是一块从数据库取出来的,可以做的到吗?感激,感激

如何在Form based Auth的基础上添加一个使用token的SSO?

问题描述 我的项目现在是基于FORM的Authentication.现在有一个新的需求是支持基于token的SSO.即如果有一个用户通过如下的url来访问我的项目,那么他不需要输入用户名,能正常访问.http://server/myapp/somepage?token=ANNDK7293YKK2我后台代码有办法验证ANNDK7293YKK2是否是正确的token,并得到对应的用户信息.我该如何实现这个功能呢?使用IHTTPModuler来控制吗?需要移除现有的FORM认证的控件和配置吧? 解决方

《深入实践Spring Boot》一第一部分 Part 1基础应用开发

第一部分 Part 1 基础应用开发 第1章 Spring Boot入门 第2章 在Spring Boot中使用数据库 第3章 Spring Boot界面设计 第4章 提高数据库访问性能 第5章 Spring Boot安全设计 这一部分从搭建开发环境,简单入门,到使用数据库.界面设计.安全管理等一系列内容,介绍了使用Spring Boot框架进行基础应用开发的方法. 第1章介绍了开发环境的搭建和开发工具的选择和安装,并以一个非常简单的实例,演示了如何使用Spring Boot框架创建工程和发布应

Listloading.js移动端上拉下拉刷新组件_javascript技巧

listloading是一个移动端的上拉.下拉加载更多的组件.主要依赖于iscroll.js v5.1.2基础上开发的组件,基础库可以使用jquery.js或者zepto.js操作dom节点,目前我是使用了zepto.js作为基础库操作dom,以jquery插件的形式存在.如果不想以插件方式使用,则只需要把listloading直接移植你需要的库里面就ok啦.listloading主要针对移动端而生,在使用浏览器自带滚动,用户体验很不友好,与Android和ios差别甚远,所以选择iscroll

Yii 快速,安全,专业的PHP框架_php基础

Yii是一个高性能的,适用于开发WEB2.0应用的PHP框架. Yii自带了丰富的功能 ,包括MVC,DAO/ActiveRecord,I18N/L10N,缓存,身份验证和基于角色的访问控制,脚手架,测试等,可显著缩短开发时间 官方网站:http://www.yiiframework.com/ Yii快速 Yii 只加载您需要的功能.它具有强大的缓存支持.它明确的设计能与 AJAX 一起高效率的工作. Yii安全 Yii 的标准是安全的.它包括了输入验证,输出过滤,SQL 注入和跨站点脚本的预防