demo描述:
这个是一个单页面的应用 ,显示的是常见的后台管理表单页面,如图是分别在手机端和pc端的样子
应用场景:
和日期有关的数据查询
应用介绍:
这个是基于bootstrap和asp.net framework 框架下的单页面应用,响应式的布局风格让它适配各类型pc和手机。其中.net 的单一应用 .ashx 文件 和ajax搭配很好的解决了前后端交互问题。
创作步骤:
- 打开visual studio 2019 点击 文件 新建项目 选择 asp.net web 应用程序(.Net Framework),点下一步,不会的请看图
- 随便配置一些信息如图
点创建。
然后选择空,其他什么都不要勾选 之后就如图所示
3.对于初学过webform 这种可以拖拖控件,然后前后端可以靠控件来控制的这种,目前想用这个模板达到前后端交互有一定的困难。这里目标是从零搭建一个webpage 框架。先展示一下最终版
对比一下多加了一个文件夹和一个一般处理程序(.ashx)以及一个index.html
这个是bootstrap框架的关键,还有一个
一般处理程序(.ashx) 这个也很关键的
。那么先来讲一个最简单的index.html 页面:
由于我这个是个一个表单,所以url这里会有个action参数,后面的search就是.ashx里的方法了
其中HttpContext这个类是个重点,全靠它来进行前后端交互
var StarTime = context.Request["startday"].ToString();
var EndTime = context.Request["endday"].ToString();
像这个样子,我们就从后端拿到前端的数据了。还有一个坑就是你的提交按钮不要有
<button class=" btn btn-primary" id="search" type="submit">搜索</button>
type="submit" ,不然你一按钮就刷新页面,和你的ajax背道而驰,造成控件数据一直是初始状态 ,最后你按钮的点击事件一定要返回一个false,不然也会·造成你页面数据出不来。
关键代码:
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<!-- Favicons -->
<meta name="theme-color" content="#7952b3">
<title>xxxxxx</title>
<!-- Bootstrap core CSS -->
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="bootstrap/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css" rel="stylesheet">
<link href="bootstrap/font/bootstrap-icons.css" rel="stylesheet">
<script src="bootstrap/js/bootstrap.min.js"></script>
<script src="bootstrap/jquery-3.6.3.min.js"></script>
<script src="bootstrap/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.min.js"></script>
<script src="bootstrap/bootstrap-datetimepicker-master/js/locales/bootstrap-datetimepicker.zh-CN.js"></script>
<style>
body {
min-height: 75rem;
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 ">
<div class="container-fluid">
<a class="navbar-brand" href="#">Miaobo</a>
<!--<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>-->
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mx-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">xxx</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="container">
<form class="d-flex">
<div class="row g-3">
<div class="col-md-6">
<span class="form-text">开始</span>
<div class="input-group">
<input class="form-control" id="datetimepicker1" type="text" value=" " placeholder="查询年月">
<span class="input-group-text bi bi-calendar-event" style="font-size: 2rem; color: cornflowerblue;"></span>
</div>
</div>
<div class="col-md-6">
<span class="form-text">结束</span>
<div class="input-group">
<input class="form-control" id="datetimepicker2" type="text" value=" " placeholder="查询年月">
<span class="input-group-text bi bi-calendar-event" style="font-size: 2rem; color: cornflowerblue;"></span>
</div>
</div>
<div class="col-md-6">
<button class=" btn btn-primary" id="search">搜索</button>
</div>
</div>
</form>
<h5 class="page-header"></h5>
<table class="table table-hover table-dark" id="autotable">
<thead>
<tr>
<th scope="col">ddate</th>
<th scope="col">relation<a class="bi-download" style="float: right;color:white"></a></th>
</tr>
</thead>
</table>
<div class="alert alert-info text-center" style="display:none">
<strong></strong>
</div>
<div class="fixed-bottom " id="pagination">
<!--<nav aria-label="Page navigation example " id="pagintation">
<ul class="pagination justify-content-center">
<li class="page-item">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>-->
</div>
</main>
</body>
</html>
<script type="text/javascript">
$(document).ready(function () {
document.body.addEventListener("touchmove", function (e) {
e.preventDefault();
}, { passive: false });
$('#datetimepicker1').datetimepicker({
forceParse: 0,//设置为0,时间不会跳转1899,会显示当前时间。
language: 'zh-CN',//显示中文
format: 'yyyy-mm-dd',//显示格式
minView: "month",//设置只显示到月份
initialDate: new Date(),//初始化当前日期
autoclose: true,//选中自动关闭
todayBtn: true//显示今日按钮
});
$('#datetimepicker1').datetimepicker("setDate", new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()-1)); //设置显示默认昨天天的时间
$('#datetimepicker2').datetimepicker({
forceParse: 0,//设置为0,时间不会跳转1899,会显示当前时间。
language: 'zh-CN',//显示中文
format: 'yyyy-mm-dd',//显示格式
minView: "month",//设置只显示到月份
initialDate: new Date(),//初始化当前日期
autoclose: true,//选中自动关闭
todayBtn: true//显示今日按钮
})
$('#datetimepicker2').datetimepicker("setDate", new Date());
var tablelist=[];
$("#search").click(function () {
var startday = $('#datetimepicker1').val();
var endday = $('#datetimepicker2').val();
if ($("#autotable").children('tbody').length > 0) {
$("#autotable").children('tbody').remove()
};
$(".alert-info").css("display","block");
$(".alert-info").find("strong").text("请稍等正在查询。。。");
tablelist = [];
/* PaginationDestroy();*/
$.ajax({
url: "Handler.ashx?action=Search", //请求接口的地址
type: "GET", //请求的方法GET/POST
data: { //需要传递的参数
startday: startday,
endday: endday
},
dataType: 'json',
success: function (res) {
tablelist = res.data;
$(".alert-info").css("display", " none");
paginationGenerator(Math.ceil(res.count / 6), 1);
tableRender(tablelist.slice(0, 6));
//在控制台输出返回结果
},
error: function (err) {
//请求失败后的操作
$(".alert-info").find("strong").text("数据库查询出错");
}
});
return false;
})
// 销毁分页器
function destroy()
{
$("#pagination").empty();
}
//创建表格
function tableRender(res) {
if ($("#autotable").children('tbody').length > 0) {
$("#autotable").children('tbody').remove()
};
//请求成功后的操作
let tbody = document.createElement("tbody");
$("#autotable").append(tbody);
// 创建tbody中的tr td
for (let i = 0; i < res.length; i++) {
// 创建tbody中的tr
let tr = document.createElement('tr');
tbody.append(tr);
// 创建tbody中的td
let tdData = res[i];
for (let [key, value] of Object.entries(tdData)) {
let td = document.createElement('td');
td.innerText = value;
tr.append(td);
}
}
}
//分页
function paginationGenerator(res, pageno)
{
destroy();
let totalPage, pageNo;//每页数据量,总页数,当前页
pageNo = pageno;
totalPage = res;
//容器生成
let nav = document.createElement("nav");
$("#pagination").append(nav);
let ul = document.createElement("ul");
ul.classList.add("pagination");
ul.classList.add("justify-content-center");
nav.append(ul);
//分页里的内容生成
let pageStr = "", start, end;
if (pageNo === 1) {
pageStr += `<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>`
}
else
{
pageStr += `<li class="page-item">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>`
}
//构建中间页面按钮区域
if (totalPage < 6)
{
for (start = 0; start < totalPage; start++) {
end = start + 1;
if (end == pageNo) {
pageStr += ` <li class="page-item active"><a class="page-link" href="#">${end}</a></li>`;
} else {
pageStr += ` <li class="page-item"><a class="page-link" href="#">${end}</a></li>`;
}
}
}
else {//当总页码大于等于3时
start = pageNo - 1//确认遍历的起始位置为当前页的前一页
end = pageNo + 1//确认遍历的结束位置为当前页的后一页
if (pageNo > 2) { pageStr += ` <li class="page-item"><a class="page-link" href="#">1</a></li>`}//当前页大于2时,将页面1按钮写死
else { end = 4 }//当前页小于等于2时,将遍历的结束位置写死为4
if (pageNo > totalPage - 3) { start = totalPage - 3 }//当前页为最后四个页面时,将遍历的起始位置写死为倒数第四个页面值
if (pageNo > 3) {
pageStr += `<li class="page-item">
<a class="page-link" href="#">
...
</a>
</li>` }//当前页大于第三个页面时,将省略号按钮展现出来
//对中间按钮进行遍历
for (; start <= end; start++) {
if (start <= totalPage && start > 0) {
if (start == pageNo) {
pageStr += ` <li class="page-item active"><a class="page-link" href="#">${start}</a></li>`;
} else {
pageStr += ` <li class="page-item "><a class="page-link" href="#">${start}</a></li>`;
}
}
}
if (pageNo < totalPage - 2) {
pageStr += `<li class="page-item">
<a class="page-link" href="#">
...
</a>
</li>` }//当前页面小于倒数第三个页面时,将省略号按钮展现出来
if (pageNo < totalPage - 1) {
pageStr += ` <li class="page-item "><a class="page-link" href="#">${totalPage}</a></li>`;
}//当前页面小于倒数第二个页面,将最后的页面按钮锁死
}
if (pageNo < totalPage) {
pageStr += `<li class="page-item">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>`
}
else {
pageStr += `<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>`
}
ul.append(document.createRange().createContextualFragment(pageStr));
switchPage(pageNo, totalPage);
};
//切换页面
function switchPage(pageNo, totalPage){
var aList = selectEle(".pagination li a", true)//获取所有的a标签
var current//定义一个当前页的标识
//对所有的a标签遍历,绑定点击事件
for (i in aList) {
if (i < aList.length) {
aList[i].addEventListener("click", function () {
var eleHtml = this.innerHTML//定义一个属性值来获取数字按钮
if (this.getAttribute("aria-label") == "Previous") {
pageNo > 1 && (pageNo = pageNo - 1)
} else if (this.getAttribute("aria-label") == "Next") {
pageNo < totalPage && (pageNo = pageNo + 1)
} else {
pageNo = parseInt(eleHtml)
}
pageNo && gotoPage(totalPage,pageNo)
})
}
}
};
//跳转页面,参数:current
function gotoPage(res,current){
var pageNo = current;
paginationGenerator(res, pageNo);
tableRender(tablelist.slice((pageNo - 1) * 6, pageNo * 6));
};
//获取页面元素
function selectEle(select, all){
return all ? document.querySelectorAll(select) : document.querySelector(select)
}
//导出 excel数据
$(".bi-download").click(function () {
$(this).hover(function () { $(this).css("color", "blue") }, function () { $(this).css("color", "white") });
//$(".alert-info").css("display", "block");
//$(".alert-info").find("strong").text("正在下载。。。");
var lHtml = '<table border="1"><tr style="font-size:16px;font-weight:bold;"><th>ddate</th><th>relation</th></tr>';
//循环遍历,每行加入tr标签,每个单元格加td标签
for (let i = 0; i < tablelist.length; i++) {
lHtml += '<tr>';
for (let item in tablelist[i]) {
lHtml += '<td>' + tablelist[i][item] + '\t</td>';//增加\t为了不让表格显示科学计数法或者其他格式
}
lHtml += '</tr>';
}
lHtml += '</table>';
var tableHtml = '<html><head><meta charset="UTF-8"></head><body>';
tableHtml += lHtml;
tableHtml += '</body></html>';
/* $(".alert-info").css("display", " none");*/
let blob = new Blob([tableHtml], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
$(this).attr({
"href": URL.createObjectURL(blob),
"download": "xxxxx.xlsx"
});
URL.revokeObjectURL(blob);
//在控制台输出返回结果
})
})
</script>
.ashx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using Newtonsoft.Json;
namespace MiaoboScript
{
/// <summary>
/// Handler 的摘要说明
/// </summary>
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
Search(context);
}
public void Search(HttpContext context)
{
//创建连接对象,并使用using释放(关闭),连接用完后会被自动关闭
var StarTime = context.Request["startday"].ToString();
var EndTime = context.Request["endday"].ToString();
using (SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["Miaobo"].ToString()))
{
//打开连接
conn.Open();
//将执行的sql
String sql = @"--使用时更改这里的日期范围即可
select ddate,activenum into #registernum from(--省略
where addtime>='" + StarTime + @"' and addtime<'" + EndTime + @"' and
--省略) as a
create table #task
(
ddate nvarchar(100),
relation nvarchar(100)
)
---申明游标
declare @ddate nvarchar(100)
declare @activenum int
declare @relationnum int
declare id_cursor cursor
for(select * from #registernum)
--打开游标
open id_cursor
--开始循环游标变量
fetch next from id_cursor into @ddate, @activenum
while(@@FETCH_STATUS=0) --返回被 FETCH语句执行的最后游标的状态
Begin
select @relationnum=count( distinct a.useridx) from --省略 a.CreateDate>=DATEADD(day,1,Convert(nvarchar(100),@ddate,23))
and a.CreateDate<DATEADD(day,2,Convert(nvarchar(100),@ddate,23))
insert into #task(ddate,relation)values(@ddate, cast((@relationnum*100.00/@activenum) as decimal(18,2)))
fetch next from id_cursor into @ddate, @activenum
End
close id_cursor --关闭游标
deallocate id_cursor --释放游标
--drop table #task
--drop table #registernum
select * from #task order by ddate";
//创建命令对象,指定要执行sql语句与连接对象conn
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandTimeout =60000;
//执行,返回影响行数
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
VM_Book result = new VM_Book();
result.code = 0;
result.msg = "";
result.count = dt.Rows.Count;
result.data = dt;
string json = JsonConvert.SerializeObject(result);
context.Response.Write(json);
context.Response.End();
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
internal class VM_Book
{
public int code { get; set; }
public string msg { get; set; }
public int count { get; set; }
public DataTable data { get; set; }
}
}