【JS实用技巧】优化动态建立元素的体式格局,让代码越发文雅且利于保护

《【JS实用技巧】优化动态建立元素的体式格局,让代码越发文雅且利于保护》

弁言

在前端开辟中,常常须要动态增加一些元素到页面上。那末如何经由过程一些技能,优化动态建立页面元素的体式格局,使得代码越发文雅,而且更易于保护呢?接下来我们经由过程研讨一些实例,一步步地找出最优计划。

这篇文章只管写得思绪清楚且通俗易懂,由浅入深为刚入门前端的新手们带来一些思绪和启示。

熟手们也可以顺着看下去,当作温习一次。亦或许直接跳到后半部份,去看轻微深切一点的模板数据替代示例,一同交换交换哦。

由于DOM和HTML会存在一定的歧义,所以为了区离开来,文章中这两个术语的意义分别是:

  • DOM :专指文档对象,是在JS上以对象的情势存在的。

  • HTML:专指HTML文本,是一连串字符的鸠合。

实例一:如何动态增加元素到页面中

话不多说,我们先来思索一下最基本的题目,如何用JS动态增加元素到页面中去呢?

假定在点击“增加一个搭客”按钮的时候,须要JS动态建立出一个新的输入框来填写姓名:

<h2>搭客列表:</h2>
<form class="form">
    <div class="form-group">
        搭客姓名:<input type="text" class="form-control" name="member[]">
    </div>
    <button class="create-passenger" type="button">增加一个搭客</button>
    <button type="submit">保留</button>
</form>

从上面可以看出,要完成这个功用,我们须要处置惩罚的HTML片断是:

<div class="form-group">
    搭客姓名:<input type="text" class="form-control" name="member[]">
</div>

委曲的计划:手动复制粘贴HTML拼接成JS字符串

那末我们先来看看传统的做法是这模样的:

先直接手动复制粘贴HTML拼接成JS字符串,然后再插进去到表单中。

$('.create-passenger').on('click', function() {
    
    // 先直接手动复制粘贴HTML拼接成JS字符串
    var html = 
        '<div class="form-group">' +
        '    搭客姓名:<input type="text" class="form-control" name="member[]">' +
        '</div>';
    // 然后再插进去到表单中
    $('.form').append(html);
});

点评&剖析

这是种偷懒的完成体式格局,在部份中小型网站、教科书上,最常见到它的身影。

在开辟时的时候,某些状况下运用这类计划,确实可以会比较疾速,直接复制粘贴HTML拼成JS字符串就可以够了。

但满足如许的条件必需是:

  1. 要拼接的HTML字符串很短;

  2. 页面构造已很稳固,能保证今后不会须要作出修正;

  3. 页面HMTL和JS的代码量都不多,或许已直接把JS写在页面上了,所以纵然设想不合理也能比较轻易检察和保护。

题目&思索

没有做好HTML和JS的星散,剧本猛烈耦合了HTML,不妥不妥。

假如后期页面上的HTML有了修改,必需同时记得去找出相干的剧本文件,在JS代码中搜刮并修正内里写死的HTML字符串才行。

换个角度再想一想,假如插进去的HTML很庞杂,有几百行的话。要在JS剧本中手动拼接巨大的字符串,是件异常的贫苦事变,还非常轻易出差错。

更好的计划:模板星散准绳

模板星散准绳:将定义模板的那一部份,与JS的代码逻辑星散开来,让代码越发文雅且利于保护。

一、应用页面上现有的DOM元素作为模板

经由过程剖析页面我们可以晓得,表单初始的时候是最少会存在一个搭客输入项的。

所以我们可以复制表单上第一个搭客的DOM来作为模板:

$('.create-passenger').on('click', function() {

    // 复制第一个搭客的DOM作为模板
    var template = $('.form .form-group:first-child').clone();
    // 将DOM模板插进去到表单中,构成新的一行
    $('.form').append(template);
});

注重点&细节剖析

实例中用了jquery的clone()要领,可以复制全部jquery包装过的DOM对象(不包括对象绑定的事宜,假如要连事宜也一同复制的话,可以加个参数clone(true)哦)。

有时候复制过来的DOM对象有可以不是最原始的状况,所以记得要初始化一下。比方有像input如许的输入项,要记得把value的值先初始化哦template.find('input').val('')

二、在隐蔽的标签中定义模板

假如页面原本就没有相干的DOM,这时候可以手动新建一个隐蔽的<div>,然后在内里定义我们的模板:

<div id="passenger-template" style="display: none;">
    <div class="form-group">
        搭客姓名:<input type="text" class="form-control" name="member[]">
    </div>
</div>

接下来用JS去取这个元素的内容作为模板:

var template = $('#passenger-template > div').clone();

注重点&细节剖析

用一个标签来包裹模板的来由,

  • 一是取模板的时候可以很轻易,直接clone()或许html()就可以够了;

  • 二是为了更好地分类和范例。比方定义模板时,请求人人都用同一种标签和CSS类:<div class="template">

固然不一定去用<div>,也可以运用别的标签,或许自定义一个<template>标签特地放模板,不过这时候要注重IE8下面自定义标签会有些许题目哦。

三、在<script>标签中定义模板

假如想越发清楚区域离开模板和一般的页面元素的话,还可以用<script>标签:

<script id="passenger-template" type="text/html"> <!- 注重标签内的type属性 -!>
    <div class="form-group">
        搭客姓名:<input type="text" class="form-control" name="member[]">
    </div>
</script>

注重点&细节剖析

<script>标签内的type="text/html",它能通知浏览器这个标签内里的内容不是JS剧本,可以直接疏忽不必去剖析。如许浏览器就不会报错了。

另有一点是这时候就不能直接运用clone()了哦,由于<script>标签内里的内容不是DOM对象,而是字符串范例的HTML片断。

所以记得要经由过程html()要领猎取我们字符串情势的模板:

var template = $('#passenger-template').html(); // 猎取的是字符串,不是DOM对象

模板星散准绳的优点

  1. JS和HTML做到了完全的解耦,非常利于后期的修正和保护。

  2. 剧本上没有了过剩的代码,我们在开辟的时候,只需关注营业逻辑了。

  3. 不必再去手动复制粘贴HTML来拼接JS字符串,写HTML比拼JS字符串要来的轻松,而且不轻易失足。所以是一个明智之举,也算是有技能地偷懒。

  4. 假如复制页面现有的DOM作为模板的话,可以完全离开后期须要保护模板的限定。今后纵然页面有修正了,JS这个“增加一个搭客”的功用,也一样能一般事情,适应性极强。

实例二:如何增加数据到动态增加的元素中

我们继承之前面的主题睁开研讨。不过此次的重点,是探讨几种增加数据的完成体式格局,一步步找出最好的计划。

新增的需求是如许的:假如想把特定的搭客信息,增加到新增的页面元素中,那样该怎么办呢?

$.ajax({
    url: '/getPassengers', // 背景猎取一切搭客的信息
    success: function(passengers) {
        
        var html = ''; // 贮存要插进去到页面的HTML片断
        var len = passengers.length;
        for (var i = 0; i < len; i++) {
            // 猎取带有该搭客信息的HTML片断
            html += get_passenger_html(passengers[i]); // 背面将细致讲这个函数的完成体式格局
        }
        $('.form').append(html);
    }
});

下面将集中讲一下,改如何天生带有指定搭客信息的HTML片断,也就是这个get_passenger_html()的内部完成体式格局。

委曲的计划:手动将数据拼接到HTML字符串中去

function get_passenger_html(passenger) {
    
    var html = '';
    html += '<div class="form-group">';
    html += '    搭客姓名:<input type="text" class="form-control" name="member[]" ';
    html += '    value="' + passenger.name + '">'; // 将搭客姓名拼接到HTML字符串中
    html += '</div>';
    
    return html;
}

点评&剖析

这个也是最传统的数据跟HTML字符串拼接的的体式格局,没有用到模板,剧本上会存在冗杂的HTML字符串拼接代码。

题目&思索

这类做法没办法运用之条件到的模板手艺,后期保护难是一个重大题目。

数据多一点或许html庞杂一点,手动拼接字符串消耗精力、轻易失足的弊病就会愈来愈展现。

更好的计划:星散数据操纵和模板定义

能不能先定义好模板,然后再做数据插进去的操纵呢?如许就可以够将模板定义和数据操纵星散开来了,跟JS的字符串拼接Say good bye啦。

下面展现两种星散数据操纵和模板定义的完成体式格局:

一、操纵DOM对象来插进去数据

假如要插进去的数据恰好是在某个标签或属性内,可以运用操纵DOM对象的体式格局来插进去数据:

function get_passenger_html(passenger) {
    
    var html = $('#passenger-template').html(); // 猎取HTML字符串模板
    var dom = $(html); // 先行将HTML字符转成DOM对象
    dom.find('.name').html(passenger.name); // 找到寄存搭客姓名的DOM节点并插进去数据
    dom.find('.tel').html(passenger.tel); // 找到寄存搭客电话的DOM节点并插进去数据
    // 把处置惩罚终了的DOM转回HTML字符串并返回
    return dom.prop("outerHTML"); 
}

注重点&细节剖析

  • 假如模板不是clone()得来的,要先用$(html)将HTML字符串转成DOM对象,然后才用find()去找到对应的DOM节点来操纵哦。

  • html()要领只能猎取子元素的HTML字符串,要猎取包括本身的HTML字符串的话,要去读取outerHTML属性,这是个DOM对象原生的属性,所以要用prop()才猎取获得哦。

二、替代自定义的占位符成指定数据

第一步先安照前面讲到的模板星散准绳,定义了一个模板。在定义这个模板的时候,顺带增加一些带有特别寄义的占位符:{name}{tel}

<script id="passenger-template" type="text/html">
    <ul class="passenger-list">
        <li>
            搭客姓名:
            <span class="name">{name}</span>
        </li>
        <li>
            搭客电话:
            <span class="tel">{tel}</span>
        </li>
    </ul>
</div>

第二步就是应用String.replace()逐一替代掉这些自定义的占位符:

function get_passenger_html(passenger) {
    
    var html = $('#passenger-template').html(); // 猎取HTML字符串模板
    // 用搭客姓名替代掉我们自定义的占位符
    html = html.replace(passenger.name, '{name}'); // 替代姓名占位符
    html = html.replace(passenger.tel, '{tel}'); // 替代电话占位符
    
    return html;
}

注重点&细节剖析

占位符的边境要特别一点,比方用{},这模样就可以防止在替代的时候,把其他有类似的字符被抹掉了。

更通用的计划:智能连系模板和数据

引见通用计划前,假定我们猎取到的模板是下面这一段字符串:

var template = '搭客姓名:{name},他的电话是:{tel},哈哈哈哈哈。';

想要替代掉占位符的JSON数据是:

var data = {
    name: '小神游',
    tel: 12312423423
};

按之前引见的要领,要一个个写死:

template.replace('{name}', data.name); 
template.replace('{tel}', data.tel); 

太贫苦了,原本已模板上定了一次占位符。然则到了对应的JS上也要再手写一次,而且数据属性名也要手写,才够保证可以替代胜利。这模样代码写得一点都不文雅。

懒散的我们,从不喜好重复劳动。这时候新建了个通用要领,能将特定模板和对应数据智能地婚配。

运用要领是如许的:

// 直接传入模板和数据即可
var html = template_replace(template, data);
console.log(html);
// 输出替代了数据的模板字符:搭客姓名:小神游,他的电话是:12312423423,哈哈哈哈哈。

哈哈哈,直接搞定!可以智能婚配模板和数据,而且还能复用在别的处所,今后可以偷懒了!

那末如何写这个要领,把模板和数据智能地婚配呢?

以替代占位符{name}为例,大致思绪是:

  1. 找出模板占位符的摆布边境,也就是{}

  2. 猎取边境内的字符串,获得数据属性名,也就是name

  3. 把全部占位符用属性值替代掉,也就是{name}替代成data['name']

要领的团体构造

// 将模板和数据连系起来
var template_replace = function(template, data) {

    // 内部要领:猎取第一个婚配到的占位符位置,也就是"{"和"}"的索引
    function get_next_placeholder_index_range() { ... }

    // 内部要领:将索引范围内的字符串,替代成data中详细的属性值
    function set_replacement(indexRange) { ... }

    // 内部要领:替代一切占位符成为对应数据
    function begin_replace() { ... }
    
    // 最先实行替代
    begin_replace();
    
    return template; // 返回替代终了的模板字符串
};

内部要领:猎取占位符位置

这个内部要领get_next_placeholder_index_range()
用于猎取第一个婚配到的占位符位置,也就是”{“和”}”的索引

从索引0最先,查找第一个婚配到的左边境{的索引值

var leftIndex = template.indexOf('{', 0);

从左边境的索引最先,查找第一个婚配到的右边境}的索引值

var rightIndex = template.indexOf('}', leftIndex);

依据状况返回包括摆布边境索引值的对象

if (leftIndex === -1 || rightIndex === -1) { // 没有搜素到婚配的占位符
    return false;
} else { // 存在占位符,返回最先和完毕的索引
    return {left: leftIndex, right: rightIndex};
}

注重点:假如没有婚配的项,indexOf()会返回-1

内部要领:替代数据

这个内部要领set_replacement(),用于将索引范围内的字符串,替代成data中详细的属性值。

猎取摆布边境内的字符串,不包括{}

var key = template.slice(indexRange.left + 1, indexRange.right);

注重点:slice()的第一个参数示意从哪一个index最先截取(包括这个index的字符),所以假如要疏忽{的话,要从indexRange.left + 1最先截取。

注重点:slice()的第二个参数示意猎取这个index值之前的字符串,所以恰好可以直接写indexRange.right来疏忽}了。

用属性值提替代掉占位符内的字符串,包括{}

template = template.replace('{' + key + '}', data[key]);

注重点:示例没有做二维三维数据的转换,有须要的话可以扩大下代码:

var key = template.slice(indexRange.left + 1, indexRange.right);
var keys = key.split('.'); // 依据点语法猎取各级的属性名
var value = ''; // 属性值
switch (keys.length) {
    case 1: // 一维,如{name}
        value = data[keys[0]];
        break;
    case 2: // 二维,如{name.firstName}
        value = data[keys[0]][keys[1]];
        break;
    case 3: // 三维,如{name.firstName.firstWord}
        value = data[keys[0]][keys[1]][keys[2]];
        break;
    default:;
}
template = template.replace('{' + key + '}', value);

不过扩大时要注重适度的衡量。当我们扩大的代码愈来愈多的时候,就证实这个自定义的函数已最先满足不了需求了,这时候发起转向运用第三方解决计划,背面会有引见一个最好的模板框架。

注重点:这个简朴示例没有做容错机制,目标是展现数据替代的要领。所之条件是假定模板的占位符都已和数据是对应的哦。

继承递归替代

begin_replace(); // 继承递归替代

应用begin_replace要领,搜检模板中另有没有下一个占位符,假如存在下一个占位符的话,begin_replace会继承递归挪用get_replacement来替代下一个,这两个函数的相互挪用会一向轮回,直到模板一切占位符替代完毕为止。

内部要领:兼顾递归替代数据

这个要领begin_replace()将会挪用前面的定义两个内部函数,目标是为了兼顾递归替代数据的操纵。

搜检模板中另有没有占位符

var indexRange = get_next_placeholder_index_range();

最先举行替代

假若有占位符,可以最先举行替代了:

if (indexRange) { // 
  set_replacement(indexRange);
}

完全的运用示例

var template = '搭客姓名:{name},他的电话是:{tel},哈哈哈哈哈。';
var data = {
    name: '小神游',
    tel: 12312423423
};
// 直接传入模板和数据即可
var html = template_replace(template, data);
console.log(html);
// 搭客姓名:小神游,他的电话是:12312423423,哈哈哈哈哈。

完全的代码示例

var template_replace = function(template, data) {

  function get_next_placeholder_index_range() { 
  
    var leftIndex = template.indexOf('{', 0);
    var rightIndex = template.indexOf('}', leftIndex);
    if (leftIndex === -1 || rightIndex === -1) {
      return false;
    } else {
      return {left: leftIndex, right: rightIndex};
    }
  }

  function set_replacement(indexRange) {
    
    var key = template.slice(indexRange.left + 1, indexRange.right);
    template = template.replace('{' + key + '}', data[key]);
    begin_replace();
  }

  function begin_replace() {

    var indexRange = get_next_placeholder_index_range();
    if (indexRange) {
      set_replacement(indexRange);
    }
  }

  begin_replace();
  
  return template;
};

代码末了也许20行摆布,今后就可以够大大提高生产力,也让今后写的代码都越发文雅。

第三方解决计划:ArtTemplate.js

当你须要更Power的模板功用的时候,不一定要本身写,更明智的做法是运用成熟的模板引擎。

这里给出我多年一向在运用的、认为是最好的模板引擎:Artemplate.js
Github地点是:https://github.com/aui/artTem…

ArtTemplate是腾讯出的模板引擎,支撑许多高等的模板操纵,比方轮回遍历、条件分支等等;而且它的剖析速率是浩瀚模板引擎中最快的。

哈哈,在我们尝试写过简朴的模板剖析,理解了应当如何善用模板和处置惩罚模板,让代码越发文雅且利于保护以后。用起第三方的模板引擎的时候会越发的打动:我的天,这东西怎么会这么轻易。

结语

经由过程对照“委曲的计划”,和引见种种“更好的计划”,实在总结起来都离不开一句话:让代码越发文雅且利于保护

记着这一点,在“够用”和“更好”之间,我们总要逆流而上,勇于在实践中寻觅“更好”。

实在不止是这篇文章中提到的一些小技能,我们在开辟中还须要去处置惩罚种种范例的题目,对应的解决计划也一定不止一个,而且正在运用的计划也不一定是最优。所以要时候有不迁就的精力,多花点时候去优化。你可以的!

文章中若有毛病愿望人人多多指正和多多见谅,我会马上纠正的哈。另有要多多批评,多多交换,多多点赞哦~

谢谢你看到了末了,人人一同加油!

    原文作者:小神游
    原文地址: https://segmentfault.com/a/1190000008571506
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞