使用 JavaScript 拖放产品到购物篮
创建可拖动的对象并将它们放入购物车。
引言
前段时间我访问了一个网站,它有一个拖放购物车功能。用户可以简单地将他们想购买的商品拖放到购物车中,购物车就会更新显示新的商品。我对这个功能印象深刻,于是决定创建一个小型应用程序来实现同样的功能。
在本文中,我将实现一个页面,允许用户将他们想购买的商品拖放到购物车中。购物车中的商品和价格将得到更新。本文提供的代码是跨浏览器兼容的。
注意:在阅读本文之前,我强烈建议您阅读文章 使用 JavaScript 进行拖放。
数据库设计
我使用 SQL SERVER 2005 Express 创建了一个名为“ToyShopDatabase”的简单数据库。该数据库包含一个名为“tblToys”的表,其中包含四个列。
ToyID
:标识列用作主键。Title
:玩具的名称。ImageUrl
:玩具的图片 URL。Price
:玩具的价格。
我已经用一些虚拟数据填充了数据库。下面我们来看看如何在页面上显示数据。
在页面上显示数据
我使用了 DataList
控件来在页面上显示数据。请查看下面的 BindData
方法,该方法用于从数据库检索数据。
private void BindData()
{
string connectionString = ConfigurationManager.ConnectionStrings _
["ConnectionString"].ConnectionString;
SqlConnection myConnection = new SqlConnection(connectionString);
SqlDataAdapter ad = new SqlDataAdapter("SELECT * FROM tblToys",_
myConnection);
DataSet ds = new DataSet();
ad.Fill(ds);
dlToys.DataSource = ds;
dlToys.DataBind();
}
您可以在下面的屏幕截图中看到页面上显示的项目
您还可以看到屏幕左侧显示的购物车。购物车显示 $0.00,因为还没有商品添加到购物车中。
有趣的是 DataList
的 HTML 代码。让我们来看看。
<asp:DataList Height="100%" Width="100%" ID="dlToys" runat="server"
RepeatColumns="3" CellPadding="20" CellSpacing="20">
<ItemTemplate>
<div ID="a" runat = "server" class="dragElement">
<asp:Label ID="lblTitle" runat=
"server" Text='<%# Eval("Title") %>' />
<asp:Label ID="lblPrice" runat="server" Text =
'<%# Eval("Price") %>' />
<asp:Image ID="imgPicture" runat="server" ImageUrl=
'<%# Eval("ImageUrl") %>' />
</div>
</ItemTemplate>
</asp:DataList>
如您在上面的代码中所见,我在 DataList
控件的 ItemTemplate
中添加了一个 <DIV> 元素。这意味着每个产品都包含在 <DIV> 元素内,该元素将作为可拖放对象。由于添加了 runat="server" 属性,<DIV> 控件将具有唯一的 ID。 ASP.NET 将在运行时分配唯一的 ID,如下所示
使元素可拖放
此时我们知道我们的 DIV 元素将充当可拖放对象。但是页面上可能有很多 DIV 控件不是此拖放功能的一部分。我们将使用正则表达式来过滤正确的 DIV 元素。
<script>
var dragElementPattern = ".+_a$";
var divElements = document.getElementsByTagName("div");
for(i=0;i<divElements.length;i++)
{
if(IsMatch(divElements[i].id, dragElementPattern))
{
MakeElementDraggable(divElements[i]);
}
}
</script>
首先,我检索页面上的所有 DIV 元素,然后使用正则表达式找到正确的元素。IsMatch
函数负责将元素的 ID 与模式进行匹配。
function IsMatch(id, pattern)
{
var regularExpresssion = new RegExp(pattern);
if(id.match(regularExpresssion)) return true;
else return false;
}
拖动克隆的元素
克隆拖动元素对于获得正确的视觉效果是必要的。如果您不克隆元素,您将移动实际元素本身,这看起来有点奇怪。看看我没有克隆就移动了实际元素的屏幕截图。
当克隆被创建时,效果如下。
这是启动拖动并创建克隆的代码。
function InitiateDrag(e)
{
mouseState = 'down';
var evt = e || window.event;
startX = parseInt(evt.clientX);
startY = parseInt(evt.clientY);
clone = obj.cloneNode(true);
clone.style.position = 'absolute';
clone.style.top = parseInt(startY) + 'px';
clone.style.left = parseInt(startX) + 'px';
document.body.appendChild(clone);
document.onmousemove = Drag;
document.onmouseup = Drop;
return false;
}
将元素拖放到放置区域
我花费了一些时间来创建一个跨浏览器的放置区域事件。只有当产品被放置在放置区域内时,放置才算成功。在我的文章“使用 JavaScript 进行拖放”中,我使用了父级方法,根据鼠标位置找到元素。但不幸的是,该方法不跨浏览器兼容。这里讨论的方法是跨浏览器兼容的,并且基于鼠标位置和页面上的放置区域位置。看看下面的图表,它解释了如何获取放置区域的位置。
这是将产品放入放置区域的代码
function Drop(e)
{
var evt = e || window.event;
var evtTarget = evt.target || evt.srcElement;
var dZone = document.getElementById("dZone");
if( evt.clientX > dZone.offsetLeft &&
evt.clientX < (dZone.offsetLeft + dZone.offsetWidth) &&
evt.clientY > dZone.offsetTop &&
evt.clientY < (dZone.offsetTop + dZone.offsetHeight))
{
AddPrice();
}
document.onmouseup = null;
document.onmousemove = null;
document.body.removeChild(clone);
mouseState = 'up';
ResetColor();
}
如果产品不在放置区域内,则产品会消失。但是,如果产品在放置区域内,它将被添加到购物车中。
将产品添加到购物车
AddPrice
函数负责更新总价和购物车显示。每个产品都嵌入在 DIV 元素中,该 DIV 元素稍后将被添加到 DropZone DIV 容器中。
function AddPrice()
{
var title = GetProductTitle();
var price = GetProductPrice();
var dZone = document.getElementById("dZone");
var textNode = document.createTextNode(title);
var priceNode = document.createTextNode(price);
var spaceNode = document.createTextNode(': $');
var paragraphElement = document.createElement('p');
// create the delete button
var deleteButton = document.createElement('button');
deleteButton.value = 'Delete';
deleteButton.innerHTML = 'Delete';
deleteButton.onclick = DeleteItem;
var item = document.createElement('div');
item.id = 'itemDiv' + uniqueNumber;
item.appendChild(paragraphElement);
item.appendChild(textNode);
item.appendChild(spaceNode);
item.appendChild(priceNode);
item.appendChild(spaceNode);
item.appendChild(deleteButton);
dZone.appendChild(item);
// increment the price
IncrementTotal(price);
uniqueNumber++;
}
GetProductTitle
和 GetProductPrice
用于从可拖放产品中检索名称和价格。uniqueNumber
是一个全局变量,用于为新创建的 DIV 元素创建唯一的 ID。每次将新产品添加到放置区域时,uniqueNumber
都会递增。IncrementTotal
函数用于将产品的价格加到总价中。
看看下面的图片,它显示了两个添加到购物车中的产品。
从购物车中删除商品
一旦产品添加到购物车,它将显示一个删除按钮。删除按钮用于从购物车中移除产品并调整总金额。
function DeleteItem(e)
{
var evt = e || window.event;
var evtTarget = evt.target || evt.srcElement;
if(IsFireFox())
{
price = evtTarget.parentNode.childNodes[2].nodeValue;
evtTarget.parentNode.parentNode.removeChild(evtTarget.parentNode);
}
else
{
price = evtTarget.parentElement.childNodes[2].nodeValue;
evtTarget.parentElement.parentElement.removeChild(
evtTarget.parentElement);
}
DecrementTotal(price);
}
由于不同浏览器访问子节点的方式不同,我创建了一个 IsFireFox
函数,如果用户使用的是 FireFox 浏览器,则返回 true。首先,我们检索产品的价格,然后从购物车中删除该产品。最后,调用 DecrementTotal
来调整总金额。
改进
我在几个地方使用了常量索引来定位容器内的项目。这些应该被动态访问项目所取代。我包括了:一个结账功能,选择多个商品的能力,在购物车内查看商品图片的能力。
推荐阅读
结论
在本文中,我们学习了如何创建可拖放对象并将它们放入购物车。
希望您喜欢这篇文章,祝您编码愉快!