`
LeeYee
  • 浏览: 72352 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

javascript 最佳实践

 
阅读更多

首次尝试翻译,如有理解错误还请指正。原文出自http://www.javascripttoolbox.com/bestpractices/

简介


这篇文章介绍一系列javascript代码开发的首选最佳实践,这些最佳实践是基于javascprit领域许多开发者的观点和经验。因此这只是一些建议而不是一个绝对规则,有经验的开发人员可能会对下面提到的最佳实践略有不同的看法。

目录
1、 总是使用关键字var声明变量
2、
属性检测胜过浏览器检测
3、
使用方括号
4、
避免使用eval
5、
正确引用表单及表单中的元素
6、
避免使用with语句
7、
在锚上使用onclick事件替代javascript伪协议
8、
用一元+操作进行数字类型转换
9、
避免使用document.all
10、
不要在javascript代码块中使用HTML注解
11、
避免杂乱的全局命名空间
12、
避免使用同步ajax调用
13、
使用json
14、
正确使用<script>标签

总是使用关键字var声明变量


javascript中的变量不是全局范围就是函数范围,使用关键字var声明变量是必不可少的。当声明一个变量时不管是全局变量还是函数级变
量,都不应省略变量的前缀关键字var。下边的例子说明了如果不这样做可能存在的潜在问题。

没有使用关键字var声明变量产生的问题

var i=0; // This is good - creates a global variable
function test() {
for (i=0; i<10; i++) {
alert("Hello World!");
}
}
test();
alert(i); // The global variable i is now 10!

 

假如函数内部的变量i没有作为一个函数级别的变量通过var声明,它将在这个例子中引用全局变量。这是一个好的方式通过var声明一个全局变量,但是对于函数范围的变量通过var来声明是重要的。下面提供的两种方式在功能上与上面的代码是一样的。

更正过的函数

function test() {
var i=0;
for (i=0; i<10; i++) {
alert("Hello World!");
}
}

 

更正过的函数

function test() {
for (var i=0; i<10; i++) {
alert("Hello World!");
}
}

 

属性检测胜过浏览器检测


有些代码是被写来检测浏览器版本和检测基于用户使用代理的不同行为的。通常情况下这个是一个非常糟糕的编程实践。任何甚至是一些看起来像全局“导航”的对象都是令人怀疑的。

最好的方式是使用属性检测。也就是说,当在一个老版本的浏览器上使用任何可能不被支持的高级属性时,应该先去检查下该函数或是方法是否被支持,然后再使用它。这样比起在使用函数或是方法时通过检测具体的浏览器版本和假设客户端支持该功能要好的多。关于这个话题更深层次的讨论可以参看http://www.jibbering.com/faq/faq_notes/not_browser_detect.html .

举例

if (document.getElementById) {
var element = document.getElementById('MyId');
}
else {
alert('Your browser lacks the capabilities required to run this script!');
}

使用方括号


当访问的对象属性是动态生成的(在运行期间定义的)或是对象的属性无法使用点操作获取时,使用方括号。假如你不是一个有经验的js程序员,对于在所有地方均使用方括号获取对象属性的操作不算是一个糟糕的编程实践。
javascript中主要有两种方式可以访问对象的属性:点操作和方括号操作。

点操作

MyObject.property

方括号操作

MyObject["property"]

当属性名是硬编码方式并且在运行期间是不能被改变时使用点操作。当属性名是一个被评估用来解析属性名的字符串时使用方括号操作。该字符串可以硬编码,也可以是一个变量,甚至可以是一个调用返回字符串属性名的函数。
假如属性名是动态(运行期间)生成的,那么方括号是必需的。比如,当你有属性“value1”、“value2”、“value3”并且想通过一个变量i=2来访问时:

MyObject["value"+i]

是可以工作的,而

MyObject.value+i

是不可以的

同样在其他一些服务端环境中(php、Struts等)被当作服务端的数组表单域是通过附加方括号表示的。然而,使用点符号引用一个包含方括号的域名将是无法工作的,因为引用一个js数组时方括号是做为语法参考的。因此方括号是必须的。

formref.elements["name[]"]

是可以工作的,而

formref.elements.name[]

是无法工作的。

方括号的使用建议是:当需要使用方括号时始终使用它,这是显而易见的。使用方括号是没有严格要求的,只是个人喜好和习惯问题。一个好的经验法则是用点符号访问标准对象属性而使用方括号访问那些定义在页面中的对象属性。因此,尽管document["getElementById"]()是一个完美的使用方括号的方式,但document.getElementById()是一个标准语法,因为 getElementById 是一个在DOM文档中定的标准文档对象属性。混合使用点符合和方括号能清楚的标明那些是标准属性,那些是由内容定义的名称:

document.forms["myformname"].elements["myinput"].value

这里,forms属性是标准的文档属性,表单名myformname是被页面内容定义的。同样的elements属性和value属性均是被特别定义的,而myinput是在页面定义的。这样的语句非常清晰、易于理解,是一种推荐的约定方式,但不是一个严格的规则。

 

避免使用eval


javascript中的eval()函数是一种在运行时期运行任意代码的方式。几乎在所有的情况下,都应避免使用eval()函数。假如在你的代码中存在该函数的调用,那么一定要确保你使用了正确的方式去实现你想要做的事情。例如,eval经常会被一些不知道方括号使用规则的程序员调用。
规则是:“eval是邪恶的”。不要使用它,除非你是一个经验丰富的开发人员,知道使用eval对你来说只是一个例外的情况。

 

正确引用表单及表单中的元素


在html的表单元素中,所有的表单元素都有一个“name"属性。但对于xhtml文档,name属性不是必须的。取而代之的是对于表单标签应该有一个id属性并可以通过document.getElementById获取该表单对象。虽然可以通过索引获取表单,但几乎在所有的情况下使用document.forms[0]却是一个不好的实践方式。一些浏览器会把表单可见做为文档自有属性来访问表单的名称。这是不可靠并且不应该被使用的。
下面的例子使用方括号和正确的对象引用来展示如何万无一失的获取表单输入框属性。

正确引用到表单中的input对象

document.forms["formname"].elements["inputname"]

坏的实践

document.formname.inputname

假如你想通过函数调用获取多表单元素,最好先把表单对象作为一个变量存储起来。这样可以避免在获取表单中的元素时重复获取表单对象。

var formElements = document.forms["mainForm"].elements;
formElements["input1"].value="a";
formElements["input2"].value="b";

当用onChange事件或是相似事件验证一个输入栏时,将待验证对象本身的引用传递给验证函数将是一个好的方式。表单内部的每一个input元素都有一个表单对象引用来作为参考。

<input type="text" name="address" onChange="validate(this)">
function validate(input_obj) {
// Get a reference to the form which contains this element
var theform = input_obj.form;
// Now you can check other inputs in the same form without
// hard-coding a reference to the form itself
if (theform.elements["city"].value=="") {
alert("Error");
}
}

通过引用到一个表单对象并通过该引用表单对象访问其属性,你可以写一个不需要在页面上指定包含任何引用表单参数的函数。这种方式经常被作为一种避免多次引用表单对象的习惯性用法使用。

 

避免使用with语句


javascript中with语句将在作用域链之前插入一个对象,因此任何对属性/变量的引用将会忽略对象本身的属性/变量而首先检测本地的属性/变量作用域。这种方法经常被看作是一种避免较长引用的捷径。

使用with的举例

with (document.forms["mainForm"].elements) {
input1.value = "junk";
input2.value = "junk";
}

可以看出上面这段代码的问题是程序员无法验证input1/input2是作为表单元素数组的属性被使用的。解释程序会先把用这些名称当作属性来检测,假如不能被找到,那么解释程序将继续查找顶层的作用域链。最终解释程序将试图把input1/input2当作全局变量去寻找其value属性,如果没有则返回一个错误。
相反,创建一个引用指向重新使用的对象并且用引用去解决其他引用。

使用一个引用替代

var elements = document.forms["mainForm"].elements;
elements.input1.value = "junk";
elements.input2.value = "junk";

在锚上使用onclick事件替代javascript伪协议


当你想通过<a>标签触发javascript代码时,使用onclick处理器优于使用javascript伪协议。通过onclick处理器运行的javascript代码必须返回true或false (或者返回的表达式等价于true或false)给调用该js代码的标签。假如返回true,那么<a>标签的HREF属性将被当作一般的超链接使用;假如返回false,那么HREF属性将被忽略。这就是为什么经常在<a>标签中使用onclicke处理器调用js代码时会在代码最后出现"return false"的原因。

正确的语法

<a href="javascript_required.html" mce_href="javascript_required.html" onclick="doSomething(); return false;">go</a>

在这段示例代码中,当超链接被点击时"doSomething()"函数(用户在页面某处定义)将被调用并返回false。href将不会指向浏览器。然而,假如浏览器没有启用javascirpt ,那么javascript_required.html文件将被加载,你可以通过提示用户启用javascript解决该问题。通常情况下当你确认用户浏览器启用了javascript时,链接只需要使用href="#"这种简单形式。但这是一种猥琐的方式。一个好的解决方式是链接一个用户浏览器没有开启javascript时的备用页面。
有时,你想有条件的提交一个链接。例如,如果用户浏览远离你的表单页面,你首先要验证这一切都没有改变。在这种情况下,您的点击会调用一个函数,它将返回一个值去说明是否该提交本链接。

条件链接

<a href="/" onClick="return validate();">Home</a>

function validate() {
return prompt("Are you sure you want to exit this page?");
}

在这个例子中,validate()函数总是返回true或是false。True意味着用户被允许返回到首页,而False意味着不被允许链接到首页的。这个例子提示用户确认信息,依赖用户点击ok或是cancel来返回true或false;
下面是一些无法正常工作的例子。假如在你的页面上看到这些代码,他们是不正确的应该被更正的。

什么是不该做的

<a href="javascript:doSomething()">link</a>
<a href="#" onClick="doSomething()">link</a>
<a href="#" onClick="javascript:doSomething();">link</a>
<a href="#" onClick="javascript:doSomething(); return false;">link</a>

用一元+操作进行数字类型转换


在javascript中,加号操作符被当作加法或是字符连接符来使用。比如,由于javascript是一种弱类型语言,当将表单域值加起来时这可能会导致一些问题。表单域值将被当作字符串对待,假如你用+将他们放在一起,JavaScript将视为连接它,而不是加法。

有问题的例子

<form name="myform" action="[url]">
<input type="text" name="val1" value="1">
<input type="text" name="val2" value="2">
</form>

function total() {
var theform = document.forms["myform"];
var total = theform.elements["val1"].value + theform.elements["val2"].value;
alert(total); // This will alert "12", but what you wanted was 3!
}

为了更正这个问题,需要给javascript一个暗示,告诉它将值当作数字而不是字符串。你可以使用一元加号操作符将字符串转换为数字类型。使用加号前缀修饰一个变量或者一个表达式将强转该变量或表达式的返回值为数字类型,使其可以成功的使用在一个数学操作中。

更正后的例子

function total() {
var theform = document.forms["myform"];
var total = (+theform.elements["val1"].value) + (+theform.elements["val2"].value);
alert(total); // This will alert 3
}

 

避免使用document.all


document.all是微软在IE中介绍的,它不是一个标准的javascriptDOM属性。虽然许多最新的浏览器通过支持它去兼容依赖于它的蹩脚脚本,但仍有许多浏览器不支持它。
在javascript中除过将document.all作为另外一些方法不被支持时的备份及IE5.0以前的浏览器使用外,是没有任何理由使用document.all的。假如浏览器是IE,你将不会用doucment.all作为一种确定支持的方式使用,因为现在其他的浏览器也支持他。

仅仅把document.all作为最后的补救方法

if (document.getElementById) {
var obj = document.getElementById("myId");
}
else if (document.all) {
var obj = document.all("myId");
}

使用document.all的规则是:

  • 总是首先尝试使用其他标准方法
  • 仅把doucment.all作为最后的补救方法使用
  • 仅使用他在你需要支持IE5.0以前的版本中
  • 当你在使用document.all时,总是用if(document.all)来检查它是否被支持

不要在javascript代码块中使用HTML注解


在早期的javascript中(1995),一些像Netscape1.0的浏览器是不支持<script>标签的。因此当javascript第一次被发布的时候,面临的问题是需要隐藏老版本浏览器对其不支持而把它们作为文本显示在页面上的问题。"hack"使用HTML的注释包裹script块来隐藏代码。

在script中使用HTML注释是不好的

<script language="javascript">
<!--
// code here
//-->
</script>

在今天是没有那个浏览器会忽略<scrpit>标签的,因此隐藏javascript代码已经不再需要。事实上,在script中使用HTML注释是无益的,原因如下:

  • 在XHTML文档中,js源代码实际将在所有的浏览器中被隐藏。
  • 在HTML注释中'--'是不被解析的,因此这将会导致任何在脚本中的递减操作是无效的。

避免杂乱的全局命名空间


全局变量和函数是很少用到的。使用全局变量可能会导致命名冲突( Using globals may cause naming conflicts between javascript source files and cause code to break. )出于这种结果,一个好的实践方式是通过单一全局命名空间将这些全局变量封装起来。
有几个不同的方式可以完成这个任务,其中一些比起另外一些结构是相对比较复杂的。简单的方式是创建一个单一的全局对象,并且分配属性和方法给这个对象。

创建一个命名空间

var MyLib = {}; // global Object cointainer
MyLib.value = 1;
MyLib.increment = function() { MyLib.value++; }
MyLib.show = function() { alert(MyLib.value); }
MyLib.value=6;
MyLib.increment();
MyLib.show(); // alerts 7

命名空间也可以通过闭包 创建,并且在javascript中私有成员变量 也能被模拟。

 

避免使用同步ajax调用


当使用Ajax请求时,你可以选择使用同步模式或者异步模式。异步模式在后台处理请求的同时其他浏览器的请求可以继续被处理,而同步模式将等待请求结果返回后才继续执行下一次请求。
同步请求模式应避免使用。同步请求将造成浏览器被锁住直到请求结果返回。这种情况下,服务器将处于忙碌状态,响应也需要一段时间,用户的浏览器(也许是操作系统)将不允许其他任何事情被做。同时也可能是,响应没有正确的被接收到,浏览器将一直保持锁住状态直到请求超时。
假如你需要使用同步模式,那么你可能需要花大部分时间去重新考虑你的设计。实际需要同步模式的Ajax请求如果有也是很少的。

 

使用json


当通过Ajax 存储文本格式数据或发送/接收数据时,在能使用json的情况下尽量使用json替代xml。json 是一个更紧凑更高效的数据格式并且是语言中性的。

 

正确使用<script>标签


<script>标签是没有 LANGUAGE 属性的。正确的方式是创建如下的javascript代码块:

<script type="text/javascript"> // code here </script>
分享到:
评论

相关推荐

    《CSS样式表行为手册》中文chm最新版本

    CSS样式表里重点讲述“行为”功能的一本CHM参考手册,很实用方便,内容也很丰富,收藏一下哦!

    1-中国各地区-固定资产投资-房地产开发投资情况(1999-2020年)-社科数据.zip

    中国各地区固定资产投资中的房地产开发投资数据集涵盖了1999至2020年的详细统计信息。该数据集包含了全国各城市地级市州的房地产开发投资情况,这些数据对于理解中国城市化进程、经济发展和房地产市场趋势至关重要。数据集中的指标包括年份、地区以及对应的房地产开发投资额(以亿元为单位),这些数据来源于中国区域统计年鉴及各省市统计年鉴。通过这些数据,研究者和决策者可以深入了解不同地区的经济动态,评估房地产市场的健康状况,并据此制定相应的政策和战略。这些数据不仅有助于宏观经济分析,还能为房地产开发商提供市场进入和扩张的决策支持。

    1-中国各地区数字经济发展对环境污染的影响数据(2011-2021年)-社科数据.zip

    中国各地区数字经济发展对环境污染的影响数据集(2011-2021年)提供了深入分析数字经济与环境污染关系的实证数据。该数据集涵盖了中国各地区在数字经济发展水平、环境污染物排放量、人口与经济指标、外资利用情况以及绿色专利指标等多个维度的数据。具体来说,数据集包括了行政区划代码、年份、所属省份等基本信息,以及数字经济水平熵值法、PM2.5均值、工业烟粉尘排放量、工业二氧化硫排放量、工业废水排放量等关键指标。此外,数据集还涉及了人口密度、人均地区生产总值、实际利用外资额占GDP之比、科学支出占比等经济和人口统计数据,以及绿色专利申请和授权总量等创新指标。这些数据不仅有助于研究者探讨数字经济对环境污染的直接影响,还能分析其潜在的中介机制和影响因素,为理解数字经济如何影响环境质量提供了宝贵的数据资源。

    1-中国各区县-工业行业企业数2004-2020年-社科数据.zip

    中国各区县工业行业企业数数据集覆盖了2004至2020年的时间跨度,提供了全国范围内区县级工业企业数量的详细统计。这些数据不仅能够反映中国工业企业的发展趋势和分布状况,而且对于研究工业行业的区域差异、发展质量和效益具有重要意义。数据集中包含了省份、地区、时间以及工业行业企业数目等关键指标,总计超过33000条数据记录。这些数据来源于各地方统计局,并经过整理,为研究者提供了一个宝贵的资源,以支持对中国经济特别是工业行业的深入分析和研究。

    BGM坏了吗111111

    BGM坏了吗111111

    毕业设计&课设_主要语言为 Java,含相关文件及配置.zip

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。

    Puppet 模块用于安装和管理 Python、pip、virtualenvs 和 Gunicorn 虚拟主机 .zip

    puppet-python The Puppet module is used to install and manage python, pip, virtualenvs, and Gunicorn virtual hosts. Please note that the module stankevich/python has been deprecated and is now available under Vox Pupuli: puppet/python. Usage For usage of classes, see Resources. If contributed, update to bundle exec rake strings:generate\[',,,,false,true'] hierarchical configuration. This module supports configuration through hiera. The following example creates two python3 virtual environments.

    WorldPO连接器标准尺寸及其选型指南,包含1.27mm、0.8mm、0.5mm间距的高速连接器

    WORLDPO(沃德披欧)是在政策支持下,成功做出对标进口品质和多达15个系列型号的连接器品牌,并且在专业机构的检测下,成功通过ISO 9001认证,FCC认证,CE认证。 内容概要:本文档为WorldPO连接器产品的选型手册,详细介绍了多种型号连接器的产品规格和参数, 包括标准的引脚间距(1.27mm、0.8mm、0.5mm、0.635mm等)、具体的引脚数量(如6-500针)、各式引脚样式(如贴片式、直插式等)、电镀方式(金镀层厚度不同)、 此外,还提供了配对合高高度、接触材料、电流负载能力、额定电流、不同型号的最大插拔次数和温度范围以及操作环境条件等多种关键属性说明。文中所有技术数据均有详细的图表辅助解读,方便用户快速查找所需参数。此外,还支持非标准定制服务。 使用场景及目标:帮助用户快速查找并选择适合自己应用需求的电连接器型号。例如,针对不同的信号传输要求,如高速数据传输、电力供应或是模拟信号传输,可以选择具有相应特性的连接器。 可以通过直接联系供应商来获取进一步的支持和服务建议。 其他说明:文档末尾提供联系人邮箱和电话,方便客户进行业务洽谈和技术支持查询。

    操作系统概述期末复习题(含解析)

    操作系统期末复习题

    毕业设计&课设_博客系统,含前后端技术,附搭建教程,曾获优秀毕业论文及展示页面截图.zip

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。

    个人原创STM32F1 BOOTLOADER,主控芯片为STM32F103VET6

    F103BL 是BOOTLOADER,需要通过仿真器进行写入; F103Usr 是一个用户程序编写实例; SW_BootLoader 是QT写的上位机,在BL的模式下通过串口和这个上位机将用户程序写入芯片; STM32的程序是利用uVision5.36编译 SW_BootLoader 是用QT5.15.2编译的

    线性调频LFM脉冲压缩雷达仿真 matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    数据科学领域的主流数据集类型及其应用分析

    内容概要:本文详细介绍了数据集中最常见的几种类型,包括结构化数据集(关系型数据库数据、时间序列数据、地理空间数据)、非结构化数据集(文本数据、图像数据、音频数据、视频数据)、半结构化数据集(JSON数据、XML数据)、流式数据集(传感器数据、社交媒体数据、网络日志数据)、多维数据集(数据仓库数据、数据立方体数据)和合成数据集(模拟数据、生成数据)。每种类型都具体描述了其特点、应用场景和优势。 适合人群:数据科学家、数据分析师、机器学习工程师和其他从事数据相关工作的专业人士。 使用场景及目标:帮助读者深入了解各种数据集的特点和应用场景,提升数据处理和分析能力,更好地利用数据集解决实际问题。 其他说明:随着大数据和人工智能技术的发展,数据集的种类、规模和复杂性不断增加,了解不同类型数据集的特点和应用场景对于提高算法性能和效果至关重要。

    中创建系统级简化参数化铰接式机器人模型 matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    使用python语言和Django框架创建的博客网站系统,下载即可运行,可做毕业设计

    使用python语言和Django框架创建的博客网站系统,下载即可运行,可做毕业设计。

    使用c++语言编程实现灰色预测模型的源代码

    灰色预测模型实现。本资源是使用c++语言编程实现灰色预测模型的源代码。模型为GM(1,1)。灰色预测模型是一种用于处理不确定性和不完全信息的预测方法,它通过分析系统内部因素之间的发展趋势,对原始数据进行生成处理,以寻找系统变动的规律,并建立微分方程模型来预测事物的未来发展趋势。灰色预测的核心是使用时间响应方程:x(k+1)=(x⑴-u/a)exp()+u/a,来根据初始值x(1)来计算x(k)(k=2,3,4....N,N+1),其中α称为发展灰数;μ称为内生控制灰数。可用二乘估计来计算得到。

    理光Ricoh 7502打印机驱动下载

    理光 Ricoh 7502 是一款高速黑白数码复印机。 【复印功能】 复印速度:75cpm 复印分辨率:600x600dpi 复印尺寸:最大 A3,305x432mm;最小 A6 SEF,100x140mm 预热时间:小于 30 秒 首页复印时间:小于 3.2 秒 连续复印页数:1-999 页 缩放范围:25-400%(以 1% 为单位) 【打印功能】 打印控制器:选配 打印速度:75ppm 打印分辨率:1200x1200dpi 打印语言:标准 PCL5e/PCL6 (XL),选购 Adobe PostScript3,XPS,Universal Driver 【扫描功能】 扫描控制器:选配 扫描速度:黑白 / 彩色单面 90ipm(200dpi),黑白 / 彩色双面 178ipm(200dpi) 扫描分辨率:100dpi,200dpi,300dpi,400dpi,600dpi 输出格式:单页 TIFF/JPEG,PDF,高压缩 PDF,加密 PDF,PDF/A;多页 TIFF,PDF,高压缩 PDF,加密 PDF,PDF/A

    最优化的顶帽和同态滤波器用于血管增强的matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    原生js随机图片拖拽排序代码.zip

    原生js随机图片拖拽排序代码.zip

    2022023721 蒋连成.pkt

    2022023721 蒋连成.pkt

Global site tag (gtag.js) - Google Analytics