前端网络请求真的搞懂了吗?解密前端参数传递方式,让开发更从容(一)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 前端网络请求真的搞懂了吗?解密前端参数传递方式,让开发更从容

I. 引言

介绍在前端开发中需要向后端传递参数的现实问题

在前端开发中,需要向后端传递参数以获取数据或完成操作是非常普遍的现实问题。

常见的场景包括用户表单提交、查询数据、修改数据、添加数据、删除数据等等。

为了保证数据的正确性和安全性,前端应遵循安全规范,并在数据传输中选择最佳的入参方式。

同时,正确的参数传递方式也会有助于提高网页速度和响应效率,提升用户体验

因此,前端开发适当的了解常见的参数传递方式,进行正确的参数传递也是非常重要的。

引出本文要介绍的前端常见入参方式

在前端开发中,我们通常会使用多种方式向后端传递参数以获取数据或完成操作。

每种方式都有其优缺点和适用场景。

本文将介绍前端常见的入参方式,包括

  • URL查询参数
  • 表单数据提交
  • FormData对象提交
  • HTTP Headers
  • JSON数据提交
  • XML数据提交
  • Hash参数

接下来介绍并分析每种方式的情况,希望能够对前端开发者提供实用、高效、安全的参数传递解决方案。

II. URL查询参数

什么是URL查询参数

网络编程中,URL(Uniform Resource Locator,统一资源定位器)是用于指定互联网上资源位置的一种标识符。

URL查询参数是指在URL中使用?和&符号对参数进行传递的一种方式。

例如:https://www.example.com/search/?q=front-end+development&oq=front-end+development&aqs=chrome.0.0i131i355i433i512j0i131i433j0i433j0i131i355i433i512l2j0i131i433i512j69i60.6558j1j7&sourceid=chrome&ie=UTF-8

在这个例子中,“?”之后的字符串就是URL查询参数,其中每段参数都以“&”符号分隔。参数q表示关键词,“oq”、“aqs”、“sourceid”、“ie”等参数表示其他操作行为。

前端开发者通常可以通过URL查询参数的方式将一些数据传递到后端。常见的应用场景包括搜索功能和分页功能。需要注意的是,由于URL具有敏感性,敏感信息不宜放在URL中传递。

如何在URL中添加参数

要在URL中添加参数,可以在URL的末尾添加“?”符号和参数列表,每个参数使用“&”符号分隔,格式如下:

http://www.example.com/search?name=value&age=18&sex=male

其中“name=value”表示一个参数及其取值,多个参数之间使用“&”符号分隔。参数名和参数值均需要进行url编码,特殊字符需要进行转义。例如:

http://www.example.com/search?name=John%20Doe&age=18&sex=male

注意:参数顺序不影响页面效果,但参数顺序不同可能会被搜索引擎误认为是不同的页面。

在前端开发中,我们可以通过JavaScript中的window.location.search属性来获取当前URL中的查询参数。

const searchParams = new URLSearchParams(window.location.search);
console.log(searchParams.get('name')); // 输出 'John Doe'
console.log(searchParams.get('age')); // 输出 '18'
console.log(searchParams.get('sex')); // 输出 'male'

以上代码使用ES6语法创建URLSearchParams对象,可以轻松获取URL中的查询参数。get()方法用于获取指定参数名的参数值,如果参数不存在,则返回null。

获取URL查询参数的方法

获取URL查询参数的方法有以下几种:

1. 使用原生JavaScript获取:

可以使用window.location.search属性来获取当前URL中的查询参数,返回的是一个字符串,包括问号后面的所有参数。接着可以使用String.slice()方法去掉问号,再用String.split()方法按照"&"分割成数组,最后再遍历数组获取参数。

// 获取URL所有查询参数
const params = window.location.search.slice(1).split('&');
// 遍历数组获取每个参数名和值
const obj = {};
params.forEach(param => {
  const [key, value] = param.split('=');
  obj[key] = decodeURIComponent(value);
});
console.log(obj);  // 输出对象 { name: "John Doe", age: "18", sex: "male" }

2. 使用URLSearchParams:

URLSearchParams是ES6中的一个新特性,可以方便地解析查询参数。它提供了一些有用的方法,如get()获取指定参数名的参数值,keys()获取所有参数名,values()获取所有参数值,entries()获取所有参数名和参数值组成的数组。需要先创建一个URLSearchParams对象,将URL的查询参数传入进去。

// 获取URL所有查询参数
const searchParams = new URLSearchParams(window.location.search);
// 遍历获取每个参数名和值
const obj = {};
for (const [key, value] of searchParams.entries()) {
  obj[key] = value;
}
console.log(obj);  // 输出对象 { name: "John Doe", age: "18", sex: "male" }

3. 使用第三方库:

如果项目中使用了第三方库,如jQuery、Lodash、Underscore.js等,这些库都提供了方便的解析参数的方法。例如,使用jQuery:

// 获取URL所有查询参数
const params = $.deparam(window.location.search.slice(1));
console.log(params);  // 输出对象 { name: "John Doe", age: "18", sex: "male" }

URL查询参数的使用场景

URL查询参数的使用场景比较广泛,包括但不限于以下几种:

1. 搜索结果页:

搜索引擎一般会在URL的查询参数中带有搜索关键词,方便用户分享搜索结果以及在浏览器中回退到上一次搜索结果页面。

2. 分页:

分页功能需要在URL的查询参数中带有页码,这样可以保证每个页面的地址是唯一的,并且可以方便地通过地址栏切换不同的页码。

3. 筛选条件:

在电商网站等场景中,页面上有多个筛选条件,如商品分类、价格区间、品牌等等。用户在选择完筛选条件后,点击“筛选”按钮或者“搜索”按钮时,需要将这些条件以参数的形式传递给后端,以便后端进行筛选操作。

4. 跳转页面时传递参数:

在页面跳转时,有时候需要将参数传递给新页面,以便新页面进行操作。可以将参数放在URL的查询参数中,然后在新页面中进行解析和操作。

总之,URL查询参数非常适合在前端和后端之间传递简单的数据,例如一个或多个数值、逻辑状态等等,方便实现GET请求。但对于更复杂的数据类型,如JSON或XML,最好使用其他的传参方式,如POST请求

III. 表单数据提交

前端表单的基础结构

一个简单的表单由以下几个主要组成部分:

  1. 标签:定义了一个表单,并且将表单内的控件组合在一起。
  2. 表单控件:、、等标签表示不同类型的表单控件,每个控件都有自己的属性和特性,可以对表单输入内容进行校验或处理。
  3. 提交按钮:按钮定义在表单内,用于提交表单数据到服务器端。
  4. 取消/重置按钮:按钮用于清空表单所有的控件内容(或将其还原为原始值)。

一个简单的表单结构示例如下:

<form action="#" method="post">
  <label for="name">姓名:</label>
  <input id="name" type="text" name="username" required>
  <label for="email">邮箱:</label>
  <input id="email" type="email" name="email" required>
  <label for="sex">性别:</label>
  <select id="sex" name="sex">
    <option value="male">男</option>
    <option value="female">女</option>
  </select>
  <label for="message">留言:</label>
  <textarea id="message" name="message"></textarea>
  <button type="submit">提交</button>
  <button type="reset">重置</button>
</form>

需要注意的是,标签中的action属性可以指定数据提交至服务器端的处理脚本或API,并且method属性可以指定数据提交方式(GET或POST)。同时每个表单控件都需要定义一个name属性,以便服务器端正确解析数据。

在以上示例中,标签的type属性设置为text和email,用于限制输入格式;标签定义了选项和默认选中项;标签用于输入多行文本内容,没有type属性;标签用于定义按钮类型,type属性可以设置为submit、reset、button等。

表单提交的3中方式:GET、POST和PUT

表单提交有三种方式:GET、POST和PUT。

  1. GET:将表单数据附加在URL后提交给服务器。这种方式比较适合提交一些简单查询条件等数据,但不适合提交大量数据或敏感数据,因为表单数据会出现在URL中,容易被第三方获取和窃取
<form action="http://example.com/search" method="GET">
  <input type="text" name="query" />
  <button type="submit">搜索</button>
</form>
  1. 例如,上述示例中,当用户点击搜索按钮时,表单数据将通过GET方式提交到http://example.com/search?q=query,q参数就是表单中输入的搜索关键词。
  2. POST:将表单数据作为消息体提交给服务器。用户输入的数据不会出现在URL中,因此比GET方式更安全,可以提交大量数据或敏感数据
<form action="http://example.com/submit" method="POST">
  <label for="name">姓名:</label>
  <input type="text" name="name" />
  <label for="email">邮箱:</label>
  <input type="email" name="email" />
  <button type="submit">提交</button>
</form>
  1. 例如,上述示例中,当用户点击提交按钮时,表单数据将通过POST方式提交到http://example.com/submit,数据不会出现在URL中,而是封装在HTTP请求的消息体中
  2. PUT:将表单数据作为消息体提交给服务器,并用来更新服务器上存在的文档或资源。PUT请求类似于POST请求,不同之处在于PUT请求用于更新已有的资源,而不是在服务器上创建新的资源。
<form action="http://example.com/update" method="PUT">
  <input type="hidden" name="id" value="123" />
  <label for="name">姓名:</label>
  <input type="text" name="name" />
  <label for="email">邮箱:</label>
  <input type="email" name="email" />
  <button type="submit">提交</button>
</form>
  1. 例如,上述示例中,当用户点击提交按钮时,表单数据将通过PUT方式提交到http://example.com/update/123,其中123是要更新的资源的ID。

需要注意的是,在使用PUT方式提交时,通常需要使用隐藏来传递资源ID等必要的信息,这样服务器在接收到PUT请求时才能正确更新相应的资源。

使用各种HTTP方法提交表单数据之间的差异

HTTP方法 说明
GET 表单数据作为查询字符串附加在URL上发送。适用于数据量小、安全性要求不高的情况,如搜索、查看等。
POST 表单数据作为请求体内容发送。适用于数据量大、安全性要求高的情况,如登录、注册等。
PUT 表单数据作为请求体内容发送,并更新指定资源。适用于更新整个资源。
PATCH 表单数据作为请求体内容发送,并对指定资源进行部分更新。适用于只更新部分资源。
DELETE 删除指定资源。适用于需要删除指定资源的情况。

总结:

  • GET:数据在URL中传输,适用于数据量小、安全性不高的情况。
  • POST:数据在请求体中传输,适用于数据量大、安全性高的情况。
  • PUT:用于更新整个资源。
  • PATCH:用于更新部分资源。
  • DELETE:用于删除指定资源。

如何获取表单数据以及其它输入控件的值

获取表单数据以及其它输入控件的值可以通过JavaScript来实现。以下是常见的获取表单数据或其它输入控件值的方法:

1. 通过id获取元素,并使用value属性获取控件的值,例如:

<input type="text" id="username">
<button onclick="getValue()">获取值</button>
<script>
function getValue() {
  var username = document.getElementById("username").value;
  console.log(username);
}
</script>

2. 通过name属性获取元素,并使用querySelector()或querySelectorAll()方法获取表单元素的值,例如:

<form>
  <label>
    用户名:
    <input type="text" name="username">
  </label>
  <label>
    密码:
    <input type="password" name="password">
  </label>
  <button type="button" onclick="getFormValues()">获取表单值</button>
</form>
<script>
function getFormValues() {
  var formData = new FormData(document.querySelector('form'));
  console.log(formData.get('username'));
  console.log(formData.get('password'));
}
</script>

3. 使用jQuery库来简化获取元素和值的操作,例如:

<form>
  <label>
    用户名:
    <input type="text" name="username">
  </label>
  <label>
    密码:
    <input type="password" name="password">
  </label>
  <button type="button" onclick="getFormValues()">获取表单值</button>
</form>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
function getFormValues() {
  var username = $('input[name="username"]').val();
  var password = $('input[name="password"]').val();
  console.log(username);
  console.log(password);
}
</script>

以上是常用的获取表单数据或其它输入控件值的方法,需要根据实际情况选择适合自己的方法。

IV. FormData对象提交

什么是FormData

FormData 是一种对象,可以将一个表单中的数据以 key-value 的形式构建出来,以便用于 AJAX 请求中提交数据。

FormData 的数据类型用于 HTML 表单数据、文件以及 Blob 对象等二进制数据。

使用 FormData 的好处是,可以自动识别表单中的控件类型,并将数据以正确的方式编码和添加到请求中。不必对每个表单字段手动进行编码,也不必为上传文件和二进制数据检查每个字节或者实例化许多 XmlHttpRequest 对象。

使用 FormData 构建表单数据并提交到服务器端的示例代码如下:

function sendData() {
  var inputs = document.querySelectorAll('input[type="text"], input[type="email"]');
  var formData = new FormData();
  for (var i = 0; i < inputs.length; i++) {
    formData.append(inputs[i].name, inputs[i].value);
  }
  var xhr = new XMLHttpRequest();
  xhr.open('POST', '/api/submitform', true);
  xhr.onload = function(e) {
    if (this.status === 200) {
      console.log(this.response);
    }
  };
  xhr.send(formData);
}

以上代码使用 FormData 将表单数据编码并提交到 /api/submitform 服务器端的地址,其中将表单中的所有 type="text"type="email" 的控件的 namevalue 填充到 FormData 对象中。最后使用 XmlHttpRequest 对象发送请求,并在响应成功后输出响应结果。


前端网络请求真的搞懂了吗?解密前端参数传递方式,让开发更从容(二)

https://developer.aliyun.com/article/1426379

目录
打赏
0
0
0
0
51
分享
相关文章
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
161 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
122 75
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
40 5
【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
89 10
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
164 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
48 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
87 18
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
48 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
前端开发者狂喜!30K star开源组件库,界面美观度/开发速度双碾压!
嗨,大家好,我是小华同学。Layui 是一款开源前端 UI 组件库,具有极简设计、强大功能和卓越性能,支持布局、表单、表格、弹层等六大模块,组件高度可定制。它无需复杂构建工具,直接面向浏览器开发,极大提升开发效率与界面美观度。适合新手和老手,快来试试吧!
【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
34 0
【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

热门文章

最新文章

  • 1
    【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    12
  • 2
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    30
  • 3
    详解智能编码在前端研发的创新应用
    15
  • 4
    智能编码在前端研发的创新应用
    15
  • 5
    VSCode AI提效工具,通义灵码前端开发体验
    31
  • 6
    大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
    22
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    3
  • 8
    以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
    12
  • 9
    【01】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-优雅草卓伊凡拟开发一个一站式家政服务平台-前期筹备-暂定取名斑马家政软件系统-本项目前端开源-服务端采用优雅草蜻蜓Z系统-搭配ruoyi框架admin后台-全过程实战项目分享-从零开发到上线
    11
  • 10
    【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
    6