基于jquery的动态创建表格的插件【上海时时乐走

获取可合并的最大半径

目前采用的是递归的方式,从0,0原点处开始搜索,获取当前原点的色值,然后与周围进行比较,获取一个最大半径的正方形:

/** * 根据给定范围获取匹配当前节点的正方形 * @param {Array} matrix 二维矩阵数组 * @param {Object} tag 当前要匹配的节点 * @param {Number} [startRowIndex=0] 开始的行下标,默认为1 * @param {Number} [startColIndex=0] 开始的列下标,默认为1 * <a href="; {Number} 返回一个最小范围 */ function range (matrix, tag, startRowIndex = 0, startColIndex = 0) { let results = [] rows: for (let rowIndex = startRowIndex; rowIndex < matrix.length; rowIndex ) { let row = matrix[rowIndex] for (let colIndex = startColIndex; colIndex < row.length; colIndex ) { let item = row[colIndex] if (item.rgba !== tag.rgba) { if (colIndex === startColIndex) { break rows // 这个表示在某一行的第一列就匹配失败了,没有必要再进行后续的匹配,直接`break`到最外层 } else { results.push(colIndex - startColIndex) break // 将当前下标放入集合,终止当前循环 } } else if (colIndex === row.length - 1) { results.push(colIndex - startColIndex) // 这里表示一整行都可以与当前元素匹配 } } } // 对所有的x、y轴的值进行比较获取最小的值 let count = Math.min.apply(Math, [results.length].concat(results)) return count }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 根据给定范围获取匹配当前节点的正方形
* @param  {Array}  matrix            二维矩阵数组
* @param  {Object} tag               当前要匹配的节点
* @param  {Number} [startRowIndex=0] 开始的行下标,默认为1
* @param  {Number} [startColIndex=0] 开始的列下标,默认为1
* <a href="http://www.jobbole.com/members/wx1409399284">@return</a> {Number}                   返回一个最小范围
*/
function range (matrix, tag, startRowIndex = 0, startColIndex = 0) {
  let results = []
  rows:
  for (let rowIndex = startRowIndex; rowIndex < matrix.length; rowIndex ) {
    let row = matrix[rowIndex]
    for (let colIndex = startColIndex; colIndex < row.length; colIndex ) {
      let item = row[colIndex]
 
      if (item.rgba !== tag.rgba) {
        if (colIndex === startColIndex) {
          break rows
          // 这个表示在某一行的第一列就匹配失败了,没有必要再进行后续的匹配,直接`break`到最外层
        } else {
          results.push(colIndex - startColIndex)
          break
          // 将当前下标放入集合,终止当前循环
        }
      } else if (colIndex === row.length - 1) {
        results.push(colIndex - startColIndex)
        // 这里表示一整行都可以与当前元素匹配
      }
    }
  }
 
  // 对所有的x、y轴的值进行比较获取最小的值
  let count = Math.min.apply(Math, [results.length].concat(results))
 
  return count
}

函数会从起点开始按顺序遍历所有的元素,在遇到不匹配的节点后,就会break进入下次循环,并将当前的下标存入数组中。
在遍历完成后,我们将数组所有的item以及数组的长度(可以认为是y轴的值)一同放入Math.min获取一个最小的值。
这个最小的值就是我们以当前节点为原点时可以生成的最大范围的正方形了。
P.S. 这个计算方式并不是很好,还不够灵活

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm4.aspx.cs" Inherits="table.WebForm4" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ";
<html xmlns="" >
<head runat="server">
<title></title>
<script src="jquery-1.3.2-vsdoc2.js" type="text/javascript"></script>
<script src="jquery-1.3.2.js" type="text/javascript"></script>
<script src="jquery.DynamicTable.js" type="text/javascript"></script>
<link href="style2.css" type="text/css" rel="Stylesheet"/>
<script type="text/javascript">
var rowtmplate = "<tr><td class='TableData'><input type='text' style='border:0px; width:98%;'/></td>";
rowtmplate = "<td class='TableData'><input type='text' style='border:0px; width:98%;'/></td>";
rowtmplate = "<td class='TableData'><input type='text' style='border:0px; width:98%;'/></td>";
rowtmplate = "<td class='TableData'><input type='text' style='border:0px; width:98%;'/></td>";
rowtmplate = "<td class='TableData'><input type='text' style='border:0px; width:98%;'/></td>";
rowtmplate = "<td class='TableData'><a href='#' >删除</a></td></tr>";
$(document).ready(function() {
$(this).bind('keyup', function(e) {
switch (e.keyCode) {
case 38: //上 ↑
var arr = $.fn.getFocus();
var rowIndex = arr[0] - 1;
$.fn.setFocus({ rowIndex: rowIndex, colIndex: arr[1] });
$.fn.setCellsFocus();
break;
case 40: //下 ↓
var arr = $.fn.getFocus();
var rowIndex = arr[0] 1;
$.fn.setFocus({ rowIndex: rowIndex, colIndex: arr[1] });
$.fn.setCellsFocus();
break;
default:
break;
}
});
$('#mytbl').DynamicTable({
rowCount: 3, //添加行数
identity: 1, //第1列自动编号
arrFocus: [2, 1], //第一个单元格设置为焦点
rowTmplate: rowtmplate //行模版
});
$('#mytbl').BindEvent({
eventName: "click",
colIndex: 1,
fn: alertMsg
}); //默认给第一列绑定click事件
$('#mytbl').setCellsFocus(); //设置第一个单元格为焦点
$('#mytbl').deleteRow(); //默认给第6列绑定删除事件
$('#mytbl').AutoFillData({ colIndex: 2, fn: getData }); //默认给第二列绑定自动填充数据
$('#mytbl').Identity({ colIndex: 1 }); //默认给第一列自动排序
$('#mytbl').validationText({ reg: /^((d .d{2})|d )$/, colIndex: 5, defalutValue: 0.00 }); //默认给第二列添加验证(只能输入money格式)
});
//添加行
function addRow(count) {
$('#mytbl').addRow({ rowCount: count });
$('#mytbl').Identity();
$.fn.deleteRow();
}
//获取自动填充数据
function getData(key) {
var arr = [];
arrFoucs = $.fn.getFocus();
$.ajax({
type: "post",
async: false, //控制同步
url: "getData.ashx",
dataType: "json",
cache: false,
success: function(data) {
var idx = arrFoucs[0] - 2;
arr.push(data[idx].id);
arr.push(data[idx].Name);
arr.push(data[idx].Code);
arr.push(data[idx].Units);
arr.push(data[idx].Price);
},
Error: function(err) {
alert(err);
}
});
$.fn.setCellsFocus({ rowIndex: arrFoucs[0], colIndex: 4 });
return arr;
}
function alertMsg() {
arrFoucs = $.fn.getFocus();
alert('你单击了坐标X:' arrFoucs[0] ' Y:' arrFoucs[1] '的单元格');
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<table cellpadding="0" cellspacing="0" class="tablestyle1" id="mytbl">
<tr>
<td class="TableData">序号</td>
<td class="TableData">产品名称</td>
<td class="TableData">产品代码</td>
<td class="TableData">单位</td>
<td class="TableData">单价</td>
<td class="TableData"><a href="#" onclick="addRow(5);">添加5行</a></td>
</tr>
</table>
<input type="button" value="获取值" onclick="javascript:alert($.fn.getValue({}));" />
</div>
</form>
</body>
</html>

box-shadow

box-shadow可以让我们针对任意一个html标签生成阴影,我们可以控制阴影的偏移量、模糊半径、实际半径、颜色等一系列属性。
语法如下:

selector { /* offset-x | offset-y | color */ box-shadow: 60px -16px teal; /* offset-x | offset-y | blur-radius | color */ box-shadow: 10px 5px 5px black; /* offset-x | offset-y | blur-radius | spread-radius | color */ box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); /* inset | offset-x | offset-y | color */ box-shadow: inset 5em 1em gold; /* Any number of shadows, separated by commas */ box-shadow: 3px 3px red, -1em 0 0.4em olive; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
selector {
  /* offset-x | offset-y | color */
  box-shadow: 60px -16px teal;
 
  /* offset-x | offset-y | blur-radius | color */
  box-shadow: 10px 5px 5px black;
 
  /* offset-x | offset-y | blur-radius | spread-radius | color */
  box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
 
  /* inset | offset-x | offset-y | color */
  box-shadow: inset 5em 1em gold;
 
  /* Any number of shadows, separated by commas */
  box-shadow: 3px 3px red, -1em 0 0.4em olive;
}

这里是MDN的box-shadow描述,里边有一些示例。

style2.css

前言

复制代码 代码如下:

getImageData

我们调用getImageData会返回如下几个参数:

  1. data
  2. width
  3. height

data为一个数组,每相邻的四个元素为一个像素点的rgba描述。
一个类似这样结构的数组:[r, g, b, a, r, g, b, a]

MDN关于context.drawImage的介绍
MDN关于context.getImageData的介绍

getData.ashx

合并相邻的单元格

虽说图片可能是由各种颜色不规则的组合而成,但毕竟还是会有很多是重复颜色的。
所以我们要计算出某一种颜色可合并的最大面积。
针对某一种颜色,用表格表示可能是这样的:
上海时时乐走势图官网 1
就像在图中所示,我们最理想的合并方式应该是这样的 (radius的取值意味着我们只能设置一个正方形)
上海时时乐走势图官网 2
于是。。如果计算出来这一块面积就成为了一个问题-.-

目前的思路是,将数组转换为二维数组,而不是单纯的在对象中用xy标识。
所以,我们对处理数组的函数进行如下修改:

function getRGBA (pixels) { let results = [] let {width, height, data} = pixels for (let i = 0; i < data.length / 4; i ) { let x = i % width | 0 let y = i / width | 0 let row = results[y] = results[y] || [] row[x] = { rgba: `${data.slice(i * 4, i * 4 4)}` // 为了方便后续的对比相同颜色,直接返回一个字符串 } } return results }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getRGBA (pixels) {
  let results = []
  let {width, height, data} = pixels
  for (let i = 0; i < data.length / 4; i ) {
    let x = i % width | 0
    let y = i / width | 0
    let row = results[y] = results[y] || []
    row[x] = {
      rgba: `${data.slice(i * 4, i * 4 4)}` // 为了方便后续的对比相同颜色,直接返回一个字符串
    }
  }
 
  return results
}

这时我们就能得到一个按照xy排列的二维数组,下一步的操作就是以任意点为原点,进行匹配周围的cell
参考上边的表格示例,我们会拿到一个类似这样的数据 (仅作示例)

[ [1, 1, 1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1], [1, 1], [1, 1, 1, 1, 1, 1], ]

1
2
3
4
5
6
7
8
9
[
  [1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1],
  [1, 1, 1],
  [1, 1, 1, 1, 1],
  [1, 1, 1, 1],
  [1, 1],
  [1, 1, 1, 1, 1, 1],
]

复制代码 代码如下:

处理rgba数据并转换为box-shadow

在上边我们拿到了一个一维数组,接下来就是将它处理为更合理的结构。
P.S. 一维数组是从左到右从上到下排列的,而不是从上到下从左到右

我们可以发现,widthheight相乘正好是data数组的length
而数组的顺序则是先按照x轴进行增加的,所以我们这样处理得到的数据:

function getRGBA (pixels) { let results = [] let {width, height, data} = pixels for (let i = 0; i < data.length / 4; i ) { results.push({ x: i % width | 0, y: i / width | 0, r: data[i * 4], g: data[i * 4 1], b: data[i * 4 2], a: data[i * 4 3] }) } return results }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getRGBA (pixels) {
  let results = []
  let {width, height, data} = pixels
  for (let i = 0; i < data.length / 4; i ) {
    results.push({
      x: i % width | 0,
      y: i / width | 0,
      r: data[i * 4],
      g: data[i * 4 1],
      b: data[i * 4 2],
      a: data[i * 4 3]
    })
  }
 
  return results
}

我们将length除以4作为循环的最大长度,然后在生成每个像素点的描述时
通过当前下标对图片宽度取余得到当前像素点在图片中的x轴下标
通过当前下标对图片宽度取商得到当前像素点在图片中的y轴下标
同时塞入rgba四个值,这样我们就会拿到一个类似这样结构的数据:

[{ x: 0, y: 0, r: 255, g: 255, b: 255, a: 255 }]

1
2
3
4
5
6
7
8
[{
  x: 0,
  y: 0,
  r: 255,
  g: 255,
  b: 255,
  a: 255
}]

jquery.DynamicTable.js

在线地址:

优化前的版本
优化后的版本
源码仓库地址

不建议上传大图片。。喜欢听电脑引擎声的除外


首先,并不打算单纯的实现某一张图片(这样太没意思了),而是通过上传图片,来动态生成box-shadow的数据。
所以,你需要了解这些东西:

  1. box-shadow
  2. canvas

您可能感兴趣的文章:

  • jQuery实现表格行和列的动态添加与删除方法【测试可用】
  • 原生JS和JQuery动态添加、删除表格行的方法
  • JQuery动态添加和删除表格行的方法
  • JQuery实现表格动态增加行并对新行添加事件
  • 基于jQuery的动态表格插件
  • JQuery Ajax动态生成Table表格
  • Jquery 动态循环输出表格具体方法
  • jquery动态增加删除表格行的小例子
  • jQuery实现html表格动态添加新行的方法
  • Jquery 动态生成表格示例代码
  • jQuery实现的简单动态添加、删除表格功能示例

递归计算剩余面积

因为上边也只是合并了一个正方形,还会剩下很多面积没有被查看。
所以我们用递归的方式来计算剩余面积,在第一次匹配结束后,是大概这个样子的:
上海时时乐走势图官网 3

所以我们在递归处拆分出了两块会有重复数据的面积:
上海时时乐走势图官网 4上海时时乐走势图官网 5

以及之后的递归也是参照这个样子来的,这样能保证所有的节点都会被照顾到,不会漏掉。(如果有更好的方式,求回复)。

这样配合着前边拿到的半径数据,很轻松的就可以组装出合并后的集合,下一步就是将其渲染到DOM中了。

/* ---------- 页面样式定义 ---------- */
body
{
background-color:#ffffff;
MARGIN:0px;
font-size: 10pt; /* 字体大小 */
font-family:Verdana; /* 字体名称 */
}
/* ---------- 文字链接 - 链接的普通状态 ---------- */
A:link {
color: #0000FF;
TEXT-DECORATION: none;}
/* ---------- 文字链接 - 已被访问链接 ---------- */
A:visited {
COLOR: #0000FF;
TEXT-DECORATION: none}
/* ---------- 文字链接 - 处于活动状态链接 ---------- */
A:active {
COLOR: #3333ff;
TEXT-DECORATION: none}
/* ---------- 文字链接 - 指针在链接上 ---------- */
A:hover {
COLOR: #ff0000;
text-decoration: underline;}
/* ---------- 表格样式1(普通表格) ---------- */
.tablestyle1{
font-size: 9pt; /* 表格内字体大小 */
width: 100%; /* 表格宽度 */
border: 0px none; /* 表格边框宽度 */
background-color: #0077B2; /* 表格线颜色 */
cellSpacing:expression(this.cellSpacing=1); /* 两个单元格之间的距离 */
cellPadding:expression(this.cellPadding=3); }
.TableData {
BACKGROUND: #FFFFFF;
FONT-SIZE: 10pt;
}

完成后的效果对比

原图&两种实现方式的效果对比:
上海时时乐走势图官网 6

我们拿合并前后生成的CSS存为了文件,并查看了文件大小,效果在一些背景不是太复杂的图片上还是很明显的,减少了2/3左右的体积。
如果将rgba替换为hex,还会再小一些
上海时时乐走势图官网 7

现在再进行检查元素不会崩溃了,但是依然会卡:)

///<reference path="jquery-1.3.2-vsdoc2.js" />
2
3 (function($) {
4 var rowtmplate = "";
5 var arrFocus = [];
6
7 $.fn.DynamicTable = function(options) { //定义插件的名称,这里为userCp
8 var deafult = {
9 //以下为该插件的属性及其默认值
rowCount: 5, //添加行数
identity: 1, //第1列自动编号
arrFocus: [2, 1], //第一个单元格设置为焦点
rowTmplate: "" //行模版
};
var ops = $.extend(deafult, options);
rowtmplate = ops.rowTmplate;
arrFocus = ops.arrFocus;
$(this).addRow(ops.rowCount);
};
/*通过行模版添加多行至表格最后一行后面*/
/*count--添加行数*/
$.fn.addRow = function(options) {
var deafult = {
rowCount: 5
};
var ops = $.extend(deafult, options);
var rowData = "";
var count = ops.rowCount;
for (var i = 1; i <= count; i ) {
rowData = rowtmplate;
}
$(this).find('tr:last-child').after(rowData);
CellsFocus();
};
/*动态给某列绑定事件,事件被触发时执行fn函数*/
/*eventName--事件名称;colIndex--列索引(从1开始);fn--触发函数*/
$.fn.BindEvent = function(options) {
var deafult = {
eventName: 'click',
colIndex: 1,
fn: function() { alert('你单击了此单元格!') }
};
var ops = $.extend(deafult, options);
eventName = ops.eventName;
colIndex = ops.colIndex;
fn = ops.fn;
$("tr:gt(0) td:nth-child(" colIndex ")").bind(eventName, fn);
};
/*给某列绑定单击删除事件*/
/*colIndex--列索引(从1开始)*/
$.fn.deleteRow = function(options) {
var deafult = {
colIndex: 6
};
var ops = $.extend(deafult, options);
var colIndex = ops.colIndex;
$("tr:gt(0) td:nth-child(" colIndex ")").bind("click", function() {
var obj = $(this).parent(); //获取tr子节点对象
if (confirm('您确定要删除吗?'))
obj.remove();
});
};
/*自动给指定列填充序号*/
/*colIndex--列索引(从1开始)*/
$.fn.Identity = function(options) {
var deafult = {
colIndex: 1
};
var ops = $.extend(deafult, options);
var colIndex = ops.colIndex;
var i = 1;
$("td:nth-child(" colIndex ")").find('input').each(function() {
$(this).attr('value', i)
i ;
});
};
/*获取焦点单元格坐标*/
$.fn.getFocus = function() {
return arrFocus;
};
/*设置焦点单元格坐标*/
/*rowIndex--行索引(从1开始);colIndex--列索引(从1开始)*/
$.fn.setFocus = function(options) {
var deafult = {
rowIndex: 2,
colIndex: 1
};
var ops = $.extend(deafult, options);
var rowIndex = ops.rowIndex;
var colIndex = ops.colIndex;
arrFocus[0] = rowIndex;
arrFocus[1] = colIndex;
};
/*当某个单元格中输入数据,按Enter键后自动根据输入的值从后台检索数据填充到该行对应列*/
/*colIndex--第几列输入数据按Enter键触发事件;fn--带参的回调函数*/
$.fn.AutoFillData = function(options) {
colIndex = options.colIndex;
fn = options.fn;
$("td:nth-child(" colIndex ")").bind("keyup", function() {
var obj = $(this).parent(); //获取tr子节点对象
$(this).find('input').each(function() {
if (event.keyCode == 13) {
var vl = $(this).val();
var arr = new Array();
arr = fn(vl);
var i = 0;
obj.find("td").each(function() {
$(this).find("input").each(function() {
$(this).attr('value', arr[i]);
i ;
});
});
}
});
});
};
/*设置某个单元格为焦点*/
/*rowIndex--行索引(从1开始);colIndex--列索引(从1开始)*/
$.fn.setCellsFocus = function(options) {
var deafult = {
rowIndex: arrFocus[0],
colIndex: arrFocus[1]
};
var ops = $.extend(deafult, options);
var rowIndex = ops.rowIndex;
var colIndex = ops.colIndex;
$("tr:nth-child(" rowIndex ") td:nth-child(" colIndex ")").each(function() {
$(this).find('input').each(function() {
$(this)[0].focus();
$(this).attr('value', $(this).attr('value'));
arrFocus = [];
arrFocus.push(rowIndex);
arrFocus.push(colIndex); //更新焦点数组值
});
});
};
/*设置某个单元格文本值为选中状态*/
/*rowIndex--行索引(从1开始);colIndex--列索引(从1开始)*/
$.fn.setCellsSelect = function(options) {
var deafult = {
rowIndex: arrFocus[0],
colIndex: arrFocus[1]
};
var ops = $.extend(deafult, options);
var rowIndex = ops.rowIndex;
var colIndex = ops.colIndex;
$("tr:nth-child(" rowIndex ") td:nth-child(" colIndex ")").each(function() {
$(this).find('input').each(function() {
$(this)[0].select();
});
});
};
/*某个单元格添加验证功能*/
/*reg--正则表达式;colIndex--列索引(从1开始);defaultValue--验证失败默认给单元格赋值*/
$.fn.validationText = function(options) {
var deafult = {
reg: /^((d .d{2})|d )$/,
colIndex: 2,
defaultValue: 0
};
var ops = $.extend(deafult, options);
var reg = ops.reg;
var colIndex = ops.colIndex;
var defaultValue = ops.defaultValue;
$("tr:gt(0) td:nth-child(" colIndex ")").each(function() {
$(this).find('input').each(function() {
//验证
$(this).bind('blur', function() {
var vl = $(this).attr('value');
if (!reg.test(vl))
$(this).attr('value', defaultValue);
});
});
});
};
/*获取表格中的值*/
$.fn.getValue = function(options) {
var deafult = {
rowIndex: 0, //行坐标(从2开始)
colIndex: 0 //列坐标(从1开始)
};
var ops = $.extend(deafult, options);
rowIndex = ops.rowIndex;
colIndex = ops.colIndex;
var val = "";
if (rowIndex == 0) { //获取所有行的数据
$('tr:gt(0)').each(function() {
$(this).find("td").each(function() {
$(this).find("input").each(function() {
val = $(this).attr('value') "&";
});
});
val = val.substring(0, val.length - 1) "|";
});
}
else {
if (colIndex == 0) { //获取某行数据
$('tr:nth-child(' rowIndex ')').each(function() {
$(this).find("td").each(function() {
$(this).find("input").each(function() {
val = $(this).attr('value') "&";
});
});
val = val.substring(0, val.length - 1) "|";
});
}
else { //获取某个单元格的值
$("tr:nth-child(" rowIndex ") td:nth-child(" colIndex ")").each(function() {
$(this).find('input').each(function() {
val = $(this).attr('value');
});
});
}
}
return val;
};
/*某个单元格获取焦点后更新焦点坐标*/
function CellsFocus() {
var colCount = $("tr:nth-child(1) td").size(); //获取每行共有多少个单元格
$("tr:gt(0) td").each(function() {
var obj = $(this);
$(this).find('input').each(function() {
$(this).bind('focus', function() {
var cellTotal = $('td').index(obj); //获取某单元格的索引
arrFocus[0] = parseInt(cellTotal / colCount) 1; //第几行
arrFocus[1] = cellTotal % colCount 1; //第几列
});
});
});
};
})(jQuery);

将数据生成为box-shadow格式的数据

box-shadow是支持多组属性的,两组属性之间使用,进行分割。
所以,我们拿到上边的数据以后,直接遍历拼接字符串就可以生成我们想要的结果:

let boxShadow = results.map(item => `${item.x}px ${item.y}px rgba(${item.r}, ${item.g}, ${item.b}, ${item.a})` ).join(',')

1
2
3
let boxShadow = results.map(item =>
  `${item.x}px ${item.y}px rgba(${item.r}, ${item.g}, ${item.b}, ${item.a})`
).join(',')

效果图:
上海时时乐走势图官网 8

虽说这样就做出来了,但是对浏览器来说太不友好了。因为是每一个像素点对应的一个box-shadow属性。
好奇的童鞋可以选择F12检查元素查看该div(反正苹果本是扛不住)
所以为了我们能够正常使用F12,我们下一步的操作就是合并相邻同色值的box-shadow,减少box-shadow属性值的数量。

复制代码 代码如下:

使用box-shadow进行画图(性能优化终结者)

2018/06/01 · CSS · box-shadow

原文出处: 贾顺名   

最近突然想做一些好玩的东西,找来找去,想到了之前曾经在网上看到过有人用box-shadow画了一副蒙娜丽莎出来
感觉这个挺有意思,正好趁着周末,自己也搞一波

由于不知道怎么上传文件 所以只好把代码贴出来 请各位见谅!!!

首版规划

刚开始的规划大致是这样的:

  1. 我们上传一张图片
  2. 创建一个Image对象接收上传的图片资源
  3. Image对象放入canvas
  4. 通过canvas生成图片文件对应的rgba数据
  5. 处理rgba数据转换为box-shadow属性
  6. done

复制代码 代码如下:

通过canvas获取我们想要的数据

canvas可以直接渲染图片到画布中,可以是一个Image对象、HTMLImageElement及更多媒体相关的标签对象。
所以我们上边会把数据暂存到一个Image对象中去。
我们在调用drawImage时需要传入xywidthheight四个参数,前两个必然是0了,关于后边两个属性,正好当我们的Image对象加载完成后,直接读取它的widthheight就是真实的数据:

let context = $canvas.getContext('2d') $img.addEventListener('load', _ => { context.drawImage($img, 0, 0, $img.width, $img.height) })

1
2
3
4
let context = $canvas.getContext('2d')
$img.addEventListener('load', _ => {
  context.drawImage($img, 0, 0, $img.width, $img.height)
})

当我们把图片渲染至canvas后,我们可以调用另一个API获取rgba相关的数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace table
{
/// <summary>
/// $codebehindclassname$ 的摘要说明
/// </summary>
[WebService(Namespace = "]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class getData : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
string value = GetResult();
context.Response.Write(value);
context.Response.End();
}
private string GetResult()
{
string result = string.Empty;
result = @"
[{""id"":""1"",""Name"":""绿茶"",""Code"":""1371"",""Units"":""斤"",""Price"":""200""},
{""id"":""2"",""Name"":""红茶"",""Code"":""1372"",""Units"":""斤"",""Price"":""300""},
{""id"":""3"",""Name"":""茶具"",""Code"":""1373"",""Units"":""台"",""Price"":""20000""},
{""id"":""4"",""Name"":""铁观音"",""Code"":""1374"",""Units"":""瓶"",""Price"":""400""},
{""id"":""5"",""Name"":""袋泡茶"",""Code"":""1375"",""Units"":""盒"",""Price"":""500""},
{""id"":""6"",""Name"":""茶食品"",""Code"":""1376"",""Units"":""盒"",""Price"":""400""},
{""id"":""7"",""Name"":""包装袋"",""Code"":""1377"",""Units"":""盒"",""Price"":""100""}]";
return result;
}
public bool IsReusable
{
get
{
return false;
}
}
}
}

如何接收图片文件数据

我们在监听input[type="file"]change事件时,可以在target里边拿到一个files的对象。
该对象为本次上传传入的文件列表集合,一般来说我们取第一个元素就是了。
我们拿到了一个File类型的对象,接下来就是用Image来接收这个File对象了。

这里会用到一个浏览器提供的全局对象URLURL提供了一个createObjectURL的方法。
方法接收一个Blob类型的参数,而File则是继承自Blog,所以我们直接传入就可以了。
然后再使用一个Image对象进行接收就可以了:

$input.addEventListener('change', ({target: {files: [file]}}) => { let $img = new Image() $img.addEventListener('load', _ => { console.log('we got this image') }) $img.src = URL.createObjectURL(file) })

1
2
3
4
5
6
7
8
9
$input.addEventListener('change', ({target: {files: [file]}}) => {
  let $img = new Image()
 
  $img.addEventListener('load', _ => {
    console.log('we got this image')
  })
 
  $img.src = URL.createObjectURL(file)
})

MDN关于URL.createObjectURL的介绍

废话少说直接进入主题,
表格功能:
1、添加
2、删除
3、获取值
4、动态填充数据
5、动态设置焦点
6、键盘左右上下键控制单元格焦点
7、单元格添加正则验证功能
WebForm4.aspx

渲染到box-shadow中

现在我们已经拿到了想要的数据,关于生成box-shadow属性处我们也要进行一些修改,之前因为是一个像素对应一个属性值,但是现在做了一些合并,所以,生成属性值的操作大概是这个样子的:

$output.style.boxShadow = results.map(item => `${item.x}px ${item.y}px 0px ${item.radius}px rgba(${item.target.rgba})` ).join(',')

1
2
3
$output.style.boxShadow = results.map(item =>
  `${item.x}px ${item.y}px 0px ${item.radius}px rgba(${item.target.rgba})`
).join(',')

P.S. xy的值必须要加上半径的值,否则会出现错位,因为box-shadow是从中心开始渲染的,而不是左上角

canvas

是的,我们还需要canvas,因为我们需要将图片资源转存到canvas中,再生成我们实际需要的数据格式。
在这里并不会拿canvas去做渲染之类的,单纯的是要利用canvas的某些API。

参考资料

  • box-shadow
  • drawImage
  • getImageData
  • createObjectURL

    1 赞 收藏 评论

上海时时乐走势图官网 9

本文由上海时时乐走势图发布于web前端,转载请注明出处:基于jquery的动态创建表格的插件【上海时时乐走

css

您可能还会对下面的文章感兴趣: