一,前端开发部分问题和优化
1.get传参中文乱码
解决:进行两次encodeURI转码,再进行一次decodeURI解码就可以了。
- 1.1 跳转页面
location.href = ‘t.html?title=’+encodeURI(encodeURI(‘中文’));
HTML接收:decodeURI(title); - 1.2 接口传参
JAVA接收:String title = URLDecoder.decode(request.getParameter(“title”), “utf-8”);
2.表单按钮重复提交问题
- 2.1 点击按钮ajax提交,就要在提交之后禁用掉按钮,以免重复提交
//防重复提交禁用按钮,禁用后不可点击
$(this).attr(‘disabled’, true);
需要注意,如果提交失败,把禁用的按钮解除禁用 - 2.2 或者用一个count来计数,只有在点击一次的时候才提交表单
3.iPhone中字符串转Date对象兼容问题
new Date(‘2016-11-11 11:11:11’);无法解释
/**
* 字符串转Date对象兼容iPhone
* iPhone中的safari所支持的格式为 YYYY,MM, DD,HH,mm,ss
* iPhone中的safari无法解释 YYYY-MM-DD HH:mm:ss 或者YYYY/MM/DD HH:mm:ss这样的时间格式
* @param dataStr 必须是完整的YYYY-MM-DD HH:mm:ss 或者YYYY/MM/DD HH:mm:ss格式
* @returns
*/
function strToDate(dataStr) {
var arr = dataStr.split(/[- : \/]/);
var date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);
return date;
}
4. jq Ajax二次封装后更好的处理异常提示
注意错误写法:async: config.async || true,这样结果一定是true
网上有很多这种写法,都是忽略了async是Boolean值
/**
* jq ajax的二次封装pc端调用,异常用layer.msg提示
* @param config
* @returns
*/
function $pcAjax(config) {
$.ajax({
type: config.type || 'get',//未定义默认为get
//async: config.async || true,//错误写法
async: ( config.async == null ? true : config.async ) ,//未定义默认为异步加载true
url: config.url,//必须参数
data: config.data || {},//未定义默认{}
dataType: config.dataType || 'json',//未定义默认json
success: function(res){
//约定:xhr请求成功必须返回状态 status=success 或 status=error 异常消息:msg=异常内容
if(res.status == "success"){
config.success(res);
}
//后台服务异常
else {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg('服务异常:'+res.msg);
});
}
},
error: function(xhr, msg) {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg('请求异常:'+msg);
});
}
});
}
封装后使用$pcAjax({ }); 其他参数与原来一致即可
$pcAjax({
type:"post",
url: ajaxPath+"action/comm/list?table=sys_user&cols=id,name&page=-1&limit=-1&order=id",
data: param,
async: false,
success:function(data){
}
});
5.封装共有的代码,提取出一个公用js
如果多次用到相同的代码,一定要封装成函数,可供后面使用
比如:对于时间的各种获取,则提取出一个时间的js文件。
共用的配置可提取到.properties文件,或共有js中
6.同一表新增和编辑使用一个页面完成
6.1 可以在js采用页面传参的方式区分是新增和编辑:这样可以共用一个页面表单元素,方便更改
使用一个ajax提交请求:
url: (pageStatus==‘y’ ? ajaxPath+“action/plan/editTask” : ajaxPath+“action/plan/addTask”),
6.2 编辑页面还原val时可以采用for in 遍历所有属性进行循环赋值
var list = data.task;
//遍历所有属性
for(var key in list[0]) {
//$('#'+key).length>0表示元素存在,则赋值
if($('#'+key).length > 0) {
$('#'+key).text( list[0][key] );
}
}
6.3 固定键值对可以采用对象获取属性方式替代if 和 switch
var type = { “1” : “紧急且重要” , “2” : “紧急不重要” , “3” : “重要不紧急” , “4” : “不重要不紧急” };
//重要程度
$(’#task_xz’).text( type[ list[0].task_xz ] );
7.switch 中容易被忽视的细节
通常我们使用条件判断是使用 if ,但如果需要判断的情况较多,或是对每一个枚举的值都需要做不同处理,就会用到 switch 语句
switch 中对于判断是使用的严格判断(===)
8.iframe标签使用和target 属性
iframe: 标记一个内联框架:被用来在当前 HTML 文档中嵌入另一个文档。
src 规定在 <iframe> 中显示的文档的 URL。
name 规定 <iframe> 的名称。
<!-- 选中用户页面 -->
<!-- 如果iframe多层嵌套name和id要唯一 -->
<iframe src="../notice/select_user.html?ids=35" id="ifr2" name="ifr2" style="width: 100%;height: 99.5%; border: 0; display: none;">
</iframe>
<!-- 选中用户页面 -->
//在iframe子页面中查找父页面元素
$('#default', window.parent.document)
//在iframe中调用父页面中定义的变量
parent.value;
//在iframe中调用父页面中定义的方法
parent.sayhello();
从当前页面跳转到指定的框架页或父窗口,则需要使用Target 属性。
Target 属性的含义:
Target 属性规定在何处打开链接文档。
_blank 在新窗口中打开被链接文档。
_self 默认。在相同的框架中打开被链接文档。
_parent 在父框架集中打开被链接文档。
_top 在整个窗口中打开被链接文档。
framename 在指定的框架中打开被链接文档。
8.2 参考链接:禁止iframe页面时产生历史记录
9. href="#"与href="javascript:void(0)"的区别
9.1 href="#"与href="javascript:void(0)"的区别 ?
# 包含了一个位置信息,默认的锚是#top 也就是网页的上端。
在页面很长的时候会使用 # 来定位页面的具体位置,格式为:# + id。
javascript:void(0), 仅仅表示一个死链接。
四种表示一个死链接的方法
<a href="####">
<a href=“javascript:void(0)”>
<a href=“javascript:void(null)”>
<a href="#" οnclick=“return false”>
网上说:链接(href)直接使用javascript:void(0)在IE中可能会引起一些问题,
最安全的办法还是使用“#”。防止点击链接跳转页首,onclick 事件return false即可
9.2 遇到问题如下:
//不兼容ios,点击时不能返回,在控制台Network中的All里可以看到异常报错,去掉href即可解决
<a href="javascript:void(0)" onclick="history.back(-1)">
10.计时事件(定时器)
setInterval() - 间隔指定的毫秒数不停地执行指定的代码。
//显示当前时间
var myVar=setInterval(function(){myTimer()},1000);
function myTimer()
{
var d=new Date();
var t=d.toLocaleTimeString();
document.getElementById("demo").innerHTML=t;
}
setTimeout() - 在指定的毫秒数后执行指定代码
setTimeout(() => {
//假设这是iframe页
var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
parent.layer.close(index); //再执行关闭
}, 500);
停止执行
clearInterval() 方法用于停止 setInterval() 方法执行的函数代码。
clearTimeout() 方法用于停止执行setTimeout()方法的函数代码。
11. 复选框checkbox取值和使用
jquery获取checkbox选中的值
$(‘input:checkbox:checked’) 等同于 $(‘input[type=checkbox]:checked’)
<input type="checkbox" class="userBox" name="checkbox1" data-id="35" data-name="超管" >
<input type="checkbox" class="userBox" name="checkbox1" data-id="36" data-name="超管2">
<input type="checkbox" class="userBox" name="checkbox1" data-id="37" data-name="超管3" >
// 全选
$('#allcheck').click(function(){
//$('input[name="checkbox1"]').attr('checked','true');
//注意1.6+的jQuery要用prop,尤其是checkBox的checked属性的判断, 否则获取不到正确值
$('input[name="checkbox1"]').prop('checked','true');
});
//反选
$('#reversecheck').click(function(){
$('input[name="checkbox1"]').each(function () {
$(this).attr("checked", !$(this).attr('checked'));
});
});
//获取选中checkbox的值
//不一定要把值设置val里,可以通过自定义属性存储多个值
//也不一定要用属性选择器才可以选择元素,类选择器也可以,效率暂不讨论
var ids = [];
var names = [];
$('.userBox:checked').each(function(){
ids.push( $(this).attr('data-id') );
names.push( $(this).attr('data-name') );
});
- 1.对于HTML元素本身就带有的固有属性,在处理时,使用prop方法。
像checkbox,radio和select这样的元素,选中属性对应“checked”和“selected”,这些也属于固有属性,因此需要使用prop方法去操作才能获得正确的结果。 - 2.对于HTML元素我们自己自定义的DOM属性,在处理时,使用attr方法。
12.右键事件,回车事件,阻止冒泡
//右键编辑任务
$('body').on('contextmenu', '.editTask', function(e) {
//停止事件冒泡
e.stopPropagation();
});
//当前页面禁用预览器默认菜单
$(document).bind("contextmenu",function(e){
return false;
});
//keydown - 键按下的过程(回车登录时用到)
$(’.enter_login’).keydown(function(event){
if(event.keyCode==13){
}
});
13.谷歌预览器调试技巧
1.使用其他框架比如weui时,有时候需要去掉框架自带元素属性比如上边框线,
这时通过Elements的Filter过滤可以快速定位
2.NetWork 中 Js Css Img 都是当前页面引用的资源,
使用前端框架:例如sui时,可以从NetWork中找到已加载的Js,
F12Elements定位元素:这里使用class=“confirm-ok”
在找到demo.js里,再使用类名confirm-ok定位Js事件
3.实际加载的NetWork 中 Js Css Img也在Source中以原项目的文件树格式显示,
Source中功能更强,可以通过这里自定义断点调试。
通常只要是开发遇到了Js报错或者其他代码问题,就可以打开Sources进行Js断点调试。
当项目已运行时,不一定要重新在代码中写debugger;直接可以自定义断点调试。
如果是Js文件可以直接在sources里修改代码,用Ctrl+s保存后,可以直接生效。
右键查看网页源码
4.多级框架页:
4.1多级框架页在Source中以父子关系显示,窗体以iframe的name命名,可以看到当前引用的链接地址。
4.2如图:若跳转到子框架页时,地址栏并不会显示子框架引用的链接,地址参数等信息。
所以有时候方便调试,可以单独打开子框架引用的链接进行调试效果更佳。
4.3当前处于子框架页时,可以右键重写加载框架(F)。即可仅刷新子框架页
14.serializeObject()将form表单中的数据序列化成对象
参考:使用serializeObject()将form表单中的数据序列化成对象
参考:jQuery序列化表单的方法总结(serialize()、serializeArray())
参考:$.fn含义
存在问题:当radio或checkbox 未选中时,没有序列化到对象中。
使用表单提交时:利用表单的serializeArray(),追加原型方法serializeObject()序列化成对象更好使用,
简化了每个input元素都要取获取值的操作。
$.fn 就是 $.prototype原型
模拟bootstrapValidator校验数据有效性
<input type="text" name="title" notempty='true' notempty-message="请输入提醒名称">
//模拟bootstrapValidator校验数据有效性,radio或checkbox 未选中不判断
var $form = $('#form');
var formObj = $form.serializeObject();
for(var key in formObj) {
if(isBlank(formObj[key])) {
var $e = $form.find('[name='+key+']');
var notempty = $e.attr('notempty');
if(notempty == 'true') {
layer.msg($e.attr('notempty-message'));
return;
}
}
}
二,JS(轻量级脚本语言)
-
JS语法:
定义一个数组:[40, 100, 1, 5, 25, 10] 、
定义一个对象:{firstName:“John”, lastName:“Doe”, age:50, eyeColor:“blue”}
定义一个函数:function myFunction(a, b) { return a * b;} -
JS数据类型:数字,字符串,数组,对象等等:
var length = 16; // Number 通过数字字面量赋值
var points = x * 10; // Number 通过表达式字面量赋值
var lastName = “Johnson”; // String 通过字符串字面量赋值
var cars = [“Saab”, “Volvo”, “BMW”]; // Array 通过数组字面量赋值
var person = {firstName:“John”, lastName:“Doe”}; // Object 通过对象字面量赋值 -
JS语句
break 用于跳出循环。
catch 语句块,在 try 语句块执行出错时执行 catch 语句块。
continue 跳过循环中的一个迭代。
do … while 执行一个语句块,在条件语句为 true 时继续执行该语句块。
for 在条件语句为 true 时,可以将代码块执行指定的次数。
for … in 用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。
function 定义一个函数
if … else 用于基于不同的条件来执行不同的动作。
return 退出函数
switch 用于基于不同的条件来执行不同的动作。
throw 抛出(生成)错误 。
try 实现错误处理,与 catch 一同使用。
var 声明一个变量。
while 当条件语句为 true 时,执行语句块。 -
JS变量(是用于存储信息的"容器"。)
声明变量:
var lastname=“Doe”,
age=30,
job=“carpenter”;
声明变量时对其赋值:var carname=“Volvo”;(未使用值来声明的变量,其值实际上是 undefined。) -
JS对象(对象是变量的容器)
var car = {type:“Fiat”, model:500, color:“white”};
在以上实例中,3 个值 (“Fiat”, 500, “white”) 赋予变量 car。
在以上实例中,3 个变量 (type, model, color) 赋予变量 car。
对象属性: 对象是键值对的容器,
键值对通常写法为 name : value (键与值以冒号分割)。
键值对在 JavaScript 对象通常称为 对象属性。
访问对象属性: car.type 或 car[ “type” ] -
JS函数
局部变量:函数内部声明的变量(使用 var)是局部变量
全局变量:在函数外声明的变量是全局变量
变量生存周期:
局部变量会在函数运行以后被删除。
全局变量会在页面关闭后被删除。
没有值赋给尚未声明的变量,该变量将被自动作为 window 的一个属性。如:carname=“Volvo”; -
JS事件
常见的HTML事件:
onchange HTML 元素改变
onclick 用户点击 HTML 元素
onmouseover 用户在一个HTML元素上移动鼠标
onmouseout 用户从一个HTML元素上移开鼠标
onkeydown 用户按下键盘按键
onload 浏览器已完成页面的加载 -
JS字符串
字符串长度:可以使用内置属性 length 来计算字符串的长度
特殊自负:反斜杠是一个转义字符。 转义字符将特殊字符转换为字符串字符
转义的特殊字符:
\’ 单引号
\" 双引号
\\ 反斜杠
\n 换行
\r 回车
\t tab(制表符)
\b 退格符
\f 换页符
字符串可以是对象:
var x = “John”;
var y = new String(“John”); (不要创建 String 对象。它会拖慢执行速度)
typeof x // 返回 String
typeof y // 返回 Object
字符串属性
constructor 返回创建字符串属性的函数
length 返回字符串的长度
prototype 允许您向对象添加属性和方法
字符串方法
charAt() 返回指定索引位置的字符
charCodeAt() 返回指定索引位置字符的 Unicode 值
concat() 连接两个或多个字符串,返回连接后的字符串
indexOf() 返回字符串中检索指定字符第一次出现的位置
lastIndexOf() 返回字符串中检索指定字符最后一次出现的位置
replace() 替换与正则表达式匹配的子串
split() 把字符串分割为子字符串数组
substr() 从起始索引号提取字符串中指定数目的字符
substring() 提取字符串中两个指定的索引号之间的字符
toLowerCase() 把字符串转换为小写
toString() 返回字符串对象值
toUpperCase() 把字符串转换为大写
trim() 移除字符串首尾空白
valueOf() 返回某个字符串对象的原始值 -
JS比较运算符
== 等于
=== 绝对等于
!= 不等于
!== 不绝对等于
条件语句:
if 语句 - 只有当指定条件为 true 时,使用该语句来执行代码
if…else 语句 - 当条件为 true 时执行代码,当条件为 false 时执行其他代码
if…else if…else 语句- 使用该语句来选择多个代码块之一来执行
switch 语句 - 使用该语句来选择多个代码块之一来执行 -
JS循环
for - 循环代码块一定的次数
for/in - 循环遍历对象的属性
while - 当指定的条件为 true 时循环指定的代码块
do/while - 同样当指定的条件为 true 时循环指定的代码块 -
JS错误
try 语句测试代码块的错误。
catch 语句处理错误。
throw 语句创建自定义错误。
finally 语句在 try 和 catch 语句之后,无论是否有触发异常,该语句都会执行。
抛出(throw)错误: 擎通常会停止,并生成一个错误消息。
try 和 catch
try {
… //异常的抛出
} catch(e) {
… //异常的捕获与处理
} finally {
… //结束处理
}
Throw 语句:
throw 语句允许我们创建自定义错误。
正确的技术术语是:创建或抛出异常(exception)。
如果把 throw 与 try 和 catch 一起使用,那么您能够控制程序流,并生成自定义的错误消息。
实例:
function myFunction() {
var message, x;;
try {
if(x == “”) throw “值为空”;
if(isNaN(x)) throw “不是数字”;
x = Number(x);
if(x < 5) throw “太小”;
if(x > 10) throw “太大”;
}
catch(err) {
message.innerHTML = "错误: " + err;//得到抛出值
}
} -
JS使用误区
A. 赋值运算符应用错误: if (x = 0) 0 为 false
B. 比较运算符常见错误:
var x = 10;
var y = “10”;
if (x == y) 数据类型是被忽略的,只比较值
C. 浮点型数据使用注意事项(编程语言包括 JS,对浮点型数据精确度难确定)
var x = 0.1;
var y = 0.2;
var z = x + y // z 的结果为 0.3
if (z == 0.3) // 返回 false
为解决问题,可以用整数的乘除法来解决
var z = (x * 10 + y * 10) / 10; // z 的结果为 0.3
D. Undefined 不是 Null
在 JScript 中, null 用于对象, undefined 用于变量,属性和方法。
对象只有被定义才有可能为 null,否则为 undefined。
错误的使用方式:
if (myObj !== null && typeof myObj !== “undefined”)
正确的方式是我们需要先使用 typeof 来检测对象是否已定义:
if (typeof myObj !== “undefined” && myObj !== null)
E. 程序块作用域
在每个代码块中 JavaScript 不会创建一个新的作用域,一般各个代码块的作用域都是全局的。
以下代码的的变量 i 返回 10,而不是 undefined:
for (var i = 0; i < 10; i++) {
// some code
}
return i; -
JS表单验证
约束验证 HTML 输入属性
disabled 规定输入的元素不可用
max 规定输入元素的最大值
min 规定输入元素的最小值
pattern 规定输入元素值的模式
required 规定输入元素字段是必需的
type 规定输入元素的类型
约束验证 CSS 伪类选择器
:disabled 选取属性为 “disabled” 属性的 input 元素
:invalid 选取无效的 input 元素
:optional 选择没有"required"属性的 input 元素
:required 选择有"required"属性的 input 元素
:valid 选取有效值的 input 元素 -
JS的let 和 const
ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: let 和 const。
let 声明的变量只在 let 命令所在的代码块内有效。
const 声明一个只读的常量,一旦声明,常量的值就不能改变。
块级作用域
{
let x = 2;
}
// 这里不能使用 x 变量
循环作用域
使用 var 关键字:
var i = 5;
for (var i = 0; i < 10; i++) {
// 一些代码…
}
// 这里输出 i 为 10
使用 let 关键字:
let i = 5;
for (let i = 0; i < 10; i++) {
// 一些代码…
}
// 这里输出 i 为 5
局部变量作用域
在函数体内使用 var 和 let 关键字声明的变量有点类似。
它们的作用域都是 局部的: -
JSON
相关函数
JSON.parse() 用于将一个 JSON 字符串转换为 JavaScript 对象。
JSON.stringify() 用于将 JavaScript 值转换为 JSON 字符串。 -
JS代码规范
变量名
变量名推荐使用驼峰法来命名(camelCase):
空格与运算符
通常运算符 ( = + - * / ) 前后需要添加空格:
语句规则
一条语句通常以分号作为结束符。
命名规则
变量和函数为小驼峰法标识, 即除第一个单词之外,其他单词首字母大写( lowerCamelCase)
全局变量为大写 (UPPERCASE )
常量 (如 PI) 为大写 (UPPERCASE )
HTML 和 CSS 的横杠(-)字符:
HTML5 属性可以以 data- (如:data-quantity, data-price) 作为前缀。
CSS 使用 - 来连接属性名 (font-size)。
- 通常在 JavaScript 中被认为是减法,所以命名不允许使用。
PHP 语言通常都使用下划线。
JS中通常推荐使用驼峰法,jQ 及其他 JS库都使用驼峰法。
变量名不要以 $ 作为开始标记,会与很多 JavaScript 库冲突。
JS 函数
-
JS闭包
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// 计数器为 3
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
直观的说就是形成一个不销毁的栈环境。
JS布尔值为false的六种情况
下面6种值转化为布尔值时为false,其他转化都为true
1、undefined = false
2、null = false
3、false(布尔值的false,字符串"false"布尔值为true)
4、0 = false(字符串"0"布尔值为true)
5、NaN = false(无法计算结果时出现,表示"非数值";但是typeof NaN===“number”)
6、""(双引号)或’’(单引号)= false,(中间有空格的字符串是true)
对于0, ‘’, null, undefined, NaN,{}, [], Infinity求布尔值,
分别是false false false false false true true true.
因此我们知道的一点是:对象的布尔值是true,即使是对象{}。
JS 高级教程
-
prototype(原型对象)
JS对象都会从一个 prototype(原型对象)中继承属性和方法。
在一个已存在的对象构造器中是不能添加新的属性的:
要添加一个新的属性需要在在构造器函数中添加:
prototype 继承
Date 对象从 Date.prototype 继承。
Array 对象从 Array.prototype 继承。
Person 对象从 Person.prototype 继承。
对象都是位于原型链顶端的 Object 的实例。
对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
添加属性和方法
使用 prototype 属性就可以给对象的构造函数添加新的属性:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = “English”; //添加新属性,所以新建对象都拥有这个值
使用 prototype 属性就可以给对象的构造函数添加新的方法:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.showMyName = function() {
return this.firstName + " " + this.lastName;
}; -
字符串(String) 对象
使用位置(索引)可以访问字符串中任何的字符:
var carname=“Volvo XC60”;
var character=carname[7];
字符串(String)长度属性length来计算字符串的长度
内容匹配:
match()函数用来查找字符串中特定的字符,并且如果找到的话,则返回这个字符。未找到返回null
替换内容
replace() 方法在字符串中用某些字符替换另一些字符。
字符串大小写转换
字符串大小写转换使用函数 toUpperCase() / toLowerCase():
字符串转为数组
字符串使用split()函数转为数组: -
Date 日期 对象
实例化一个日期的一些例子:
var today = new Date()
var d1 = new Date(“October 13, 1975 11:13:00”)
var d2 = new Date(79,5,24)
var d3 = new Date(79,5,24,11,33,0) -
Array数组对象
创建一个数组
1: 常规方式:
var myCars=new Array();
myCars[0]=“Saab”;
myCars[1]=“Volvo”;
myCars[2]=“BMW”;
2: 简洁方式:
var myCars=new Array(“Saab”,“Volvo”,“BMW”);
3: 字面:
var myCars=[“Saab”,“Volvo”,“BMW”]; -
** Math算数对象**
Math(算数)对象的作用是:执行普通的算数任务。
算数方法
使用了 Math 对象的 round 方法对一个数进行四舍五入。
Math.round(4.7)
使用了 Math 对象的 random() 方法来返回一个介于 0 和 1 之间的随机数:
Math.random()
Math 对象的 floor() 方法和 random() 来返回一个介于 0 和 11 之间的随机数:
Math.floor(Math.random()*11) -
RegExp:是正则表达式(regular expression)
修饰符用于执行不区分大小写和全文的搜索。
i - 修饰符是用来执行不区分大小写的匹配。
g - 修饰符是用于执行全文的搜索(而不是在找到第一个就停止查找,而是找到所有的匹配)。
test()方法搜索字符串指定的值,根据结果并返回真或假。
exec() 方法检索字符串中的指定值。返回值是被找到的值。如果没有发现匹配,则返回 null。
JS 浏览器BOM
-
所有浏览器都支持 window 对象。它表示浏览器窗口。
window.open() - 打开新窗口
window.close() - 关闭当前窗口
window.moveTo() - 移动当前窗口
window.resizeTo() - 调整当前窗口的尺寸 -
Window Location
location.hostname 返回 web 主机的域名
location.pathname 返回当前页面的路径和文件名
location.port 返回 web 主机的端口 (80 或 443)
location.protocol 返回所使用的 web 协议(http: 或 https:)
location.href 属性返回当前页面的 URL。
location.pathname 属性返回 URL 的路径名。 -
Window History
history.back() - 与在浏览器点击后退按钮相同
history.forward() - 与在浏览器中点击向前按钮相同
JS Cookie,Session,WebStorage
-
Cookie
应用场景(对于安全性不高数据存储,后面WebStorage的出现可以替代Cookie)
1.判断用户是否登陆过网站,以便下次登录时能够实现自动登录(或者记住密码)
2.保存上次登录的时间等信息。
3.保存上次查看的页面
4.浏览计数
缺点
(1)大小受限
(2)用户可以操作(禁用)cookie,使功能受限
(3)安全性较低
(4)有些状态不可能保存在客户端。
(5)每次访问都要传送cookie给服务器,浪费带宽。
(6)cookie数据有路径(path)的概念,可以限制cookie只属于某个路径下。 -
Session
应用场景(常用于保存每个用户的专用信息,通过SessionID来区分不同的客户)
1.网上商城中的购物车
2.保存用户登录信息,防止用户非法登录
3.将某些数据放入session中,供同一用户的不同页面使用
缺点
(1)Session存储越多,就越占用服务器内存,对于用户在线人数较多网站,服务器内存压力比较大。
(2)依赖于cookie(sessionID保存在cookie),如果禁用cookie,则要使用URL重写,不安全
(3)创建Session变量有很大的随意性,可随时调用,不需要开发者做精确地处理,所以,过度使用session变量将会导致代码不可读而且不好维护。 -
WebStorage
WebStorage将数据在浏览器中保存,不参与服务器通信,存储数据大小一般都是:5MB
WebStorage提供了两种API:localStorage(本地存储)和sessionStorage(会话存储)
应用场景:
localStoragese:常用于长期登录(+判断用户是否已登录),适合长期保存在本地的数据。sessionStorage:敏感账号一次性登录;
WebStorage的优点
1.存储空间更大:cookie为4KB,而WebStorage是5MB;
2.节省网络流量:WebStorage不会传送到服务器,减少了客户端和服务器端的交互,节省了网络流量
3.对于那种只需要在用户浏览一组页面期间保存而关闭浏览器后就可以丢弃的数据,sessionStorage会非常方便;
4.安全性:WebStorage不会随着HTTP header发送到服务器端,所以安全性相对于cookie来说比较高,不会担心截获,但是仍然存在伪造问题;
5.WebStorage提供了一些方法,数据操作比cookie方便;
setItem (key, value) ,保存数据,以键值对的方式储存信息。
getItem (key) ,获取数据,将键值传入,即可获取到对应的value值。
removeItem (key) , 删除单个数据,根据键值移除对应的信息。
clear (), 删除所有的数据
key (index) , 获取某个索引的key
//本地存储:存储
localStorage.setItem(“task_obj”, JSON.stringify(obj));
//本地存储:获取
var localTest = localStorage.getItem(“task_obj”);
三,JQ(是JS函数库:简化JS写法)
-
属性选择器
[target] 选择所有带有target属性元素
[target=blank] 选择所有使用target="blank"的元素
a:hover 选择鼠标在链接上面时
input:focus 选择具有焦点的输入元素 -
事件
鼠标事件:
当双击元素时,会发生 dblclick 事件。
mouseup()
当在元素上松开鼠标按钮时,会发生 mouseup 事件。
右键监听事件时用到,如下
//右键编辑字幕
$(’.left_list0’).on(‘mouseup’, ‘.left_item_’, function(e) {
//禁止预览器默认菜单
window.oncontextmenu = function(){return false;}
if(e.button == 2){
}
});
hover()方法用于模拟光标悬停事件。
当鼠标移动到元素上时,会触发指定的第一个函数(mouseenter);当鼠标移出这个元素时,会触发指定的第二个函数(mouseleave)。
键盘事件
keydown - 键按下的过程(回车登录时用到)
$(’.enter_login’).keydown(function(event){
if(event.keyCode==13){
}
});
keypress - 键被按下
keyup - 键被松开
表单事件
当提交表单时,会发生 submit 事件。该事件只适用于 form元素。
当元素的值改变时发生 change 事件(仅适用于表单字段)。
focus() 当元素获得焦点时,发生 focus 事件。
blur() 当元素失去焦点时,发生 blur 事件。 -
隐藏和显示
hide() 和 show() 方法来隐藏和显示 HTML 元素:
使用 toggle() 方法来切换 hide() 和 show() 方法。
显示被隐藏的元素,并隐藏已显示的元素 -
效果- 动画
animate() 方法允许您创建自定义的动画。
$(selector).animate({params},speed,callback);
必需的 params 参数定义形成动画的 CSS 属性。
可选的 speed 参数规定效果的时长。它可以取以下值:“slow”、“fast” 或毫秒。
可选的 callback 参数是动画完成后所执行的函数名称。
停止动画
stop() 方法适用于所有 jQuery 效果函数,包括滑动、淡入淡出和自定义动画。
Callback 方法
Callback 函数在当前动画 100% 完成之后执行。 -
方法链接
在相同的元素上运行多条 jQuery 命令,浏览器就不必多次查找相同的元素。
$("#p1").css(“color”,“red”)
.slideUp(2000)
.slideDown(2000); -
获取内容和属性
text() - 设置或返回所选元素的文本内容
html() - 设置或返回所选元素的内容(包括 HTML 标记)
val() - 设置或返回表单字段的值
获取属性 - attr()
$("#runoob").attr(“href”)
设置内容和属性
attr() 方法也用于设置/改变属性值。
attr() 方法也允许您同时设置多个属性。
$("#runoob").attr({
“href” : “http://www.runoob.com/jquery”,
“title” : “jQuery 教程”
}); -
添加元素如 append()
添加新的 HTML 内容
append() - 在被选元素的结尾插入内容
prepend() - 在被选元素的开头插入内容
after() - 在被选元素之后插入内容
before() - 在被选元素之前插入内容
删除元素
remove() - 删除被选元素(及其子元素)
empty() - 从被选元素中删除子元素 -
获取并设置 CSS 类
addClass() - 向被选元素添加一个或多个类
removeClass() - 从被选元素删除一个或多个类
toggleClass() - 对被选元素进行添加/删除类的切换操作
css() - 设置或返回样式属性
css() 方法
返回指定的 CSS 属性的值,请使用如下语法:$(“p”).css(“background-color”);
设置指定的 CSS 属性,请使用如下语法: $(“p”).css(“background-color”,“yellow”);
设置多个 CSS 属性
css({“propertyname”:“value”,“propertyname”:“value”,…}); -
遍历(用于根据其相对于其他元素的关系来"查找"(或选取)HTML 元素)
遍历 - 祖先
parent() 方法返回被选元素的直接父元素。
parents() 方法返回被选元素的所有祖先元素。
遍历 - 后代
children() 方法返回被选元素的所有直接子元素。
find() 方法返回被选元素的后代元素,一路向下直到最后一个后代。
遍历 - 同胞(siblings)
siblings() 方法返回被选元素的所有同胞元素。
next() 方法返回被选元素的下一个同胞元素。
nextAll() 方法返回被选元素的所有跟随的同胞元素。
prev() 方法返回被选元素的前一个同级元素
prevAll() 方法返回被选元素之前的所有同级元素
遍历- 过滤
first() 方法返回被选元素的首个元素。
last() 方法返回被选元素的最后一个元素。
eq() 方法返回被选元素中带有指定索引号元素。索引号从 0 开始,因此首个元素索引是 0 而不是 1。 -
AJAX
AJAX 是与服务器交换数据的技术,它在不重载全部页面的情况下,实现了对部分网页的更新。
load() 方法从服务器加载数据,并把返回的数据放入被选元素中。
必需的 URL 参数规定您希望加载的 URL。
可选的 data 参数规定与请求一同发送的查询字符串键/值对集合。
可选的 callback 参数是 load() 方法完成后所执行的函数名称。
get() 和 post() 方法
$.get() 方法通过 HTTP GET 请求从服务器上请求数据。
$.get(URL,callback);
必需的 URL 参数规定您希望请求的 URL。
可选的 callback 参数是请求成功后所执行的函数名。
$.post() 方法通过 HTTP POST 请求向服务器提交数据。
$.post(URL,data,callback);
必需的 URL 参数规定您希望请求的 URL。
可选的 data 参数规定连同请求发送的数据。
可选的 callback 参数是请求成功后所执行的函数名。 -
noConflict() 方法
解决与其他 JavaScript 框架也使用$ 符号问题
建自己的简写。noConflict() 可返回对 jQuery 的引用,您可以把它存入变量,以供稍后使用。 -
JSONP(使用 JSONP 形式的回调函数来加载其他网域的 JSON 数据)
1.服务端 JSONP 格式数据
如客户想访问 : https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction。
假设客户期望返回数据:[“customername1”,“customername2”]。
真正返回到客户端的数据显示为: callbackFunction([“customername1”,“customername2”])。
2.客户端实现 callbackFunction 函数
jQuery 使用 JSONP
$.getJSON(“https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=?”, function(data) {
});
该函数是简写的 Ajax 函数,等价于:
$.ajax({
url: url,
data: data,
success: callback,
dataType: json
});
四,AJAX(异步的 JavaScript 和 XML)
最大优点在不重新加载整个页面情况下,与服务器交换数据并更新部分网页。
五,JS封装工具类
1.AJAX二次封装
2.表单序列化对象
3.地址栏参数
4.有效判空
5.时间函数:格式化,计算日期等
//AJAX*********************************************
/**
* jq ajax的二次封装pc端调用,异常用layer.msg提示
* @param config
* @returns
*/
function $pcAjax(config) {
$.ajax({
type: config.type || 'get',//未定义默认为get
async: ( config.async == null ? true : config.async ) ,//未定义默认为异步加载true
url: config.url,//必须参数
data: config.data || {},//未定义默认{}
dataType: config.dataType || 'json',//未定义默认json
success: function(res){
//约定:xhr请求成功必须返回状态 status=success 或 status=error 异常消息:msg=异常内容
if(res.status == "success"){
config.success(res);
}
//后台服务异常
else {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg('服务异常:'+res.msg);
});
}
},
error: function(xhr, msg) {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg('请求异常:'+msg);
});
}
});
}
//表单序列化对象***************************************
/**
* 原型form序列化对象
*/
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
/**
* 原型form设置默认值,radio或checkbox未选中无效
* @param o 数据对象:key必须与表单元素name一致
*/
$.fn.setFormData = function(o) {
var a = this.serializeArray();
console.log(JSON.stringify(o))
var $form = $(this);
$.each(a, function() {
var $e = $form.find('[name='+this.name+']');
if($e != null) {
var type = $e.attr('type');
if(type == 'radio') {
$form.find('input[name='+this.name+'][value='+o[this.name]+']').attr('checked',true);
} else if(type == 'checkbox') {
$form.find('input[name='+this.name+']:checked').attr('checked',false);
$form.find('input[name='+this.name+'][value='+o[this.name]+']').attr('checked',true);
} else {
$e.val(o[this.name]);
}
}
});
};
//地址栏*********************************************
/**
* 获取url后的参数值
* @param name
* @returns
*/
function getUrlParam(name) {
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);//search,查询?后面的参数,并匹配正则
if(r!=null)return unescape(r[2]); return null;
}
/**
* 获取url后的参数值非正则写法
* @param key
* @returns
*/
function getUrlParam2(key) {
var href = window.location.href;
var url = href.split("?");
if(url.length <= 1){
return "";
}
var params = url[1].split("&");
for(var i=0; i<params.length; i++){
var param = params[i].split("=");
if(key == param[0]){
return param[1];
}
}
}
//有效判空*********************************************
/**
* 模拟bootstrapValidator校验数据有效性,radio或checkbox未选中不判断
* @param formObj 表单序列化对象
* @param $form 表单jq对象
* @returns true校验不通过
*/
function validateForm(formObj, $form) {
for(var key in formObj) {
if(isBlank(formObj[key])) {
var $e = $form.find('[name='+key+']');
var notempty = $e.attr('notempty');
if(notempty == 'true') {
layer.msg($e.attr('notempty-message'));
return true;
}
}
}
return false;
}
/**
* 有效值,替换null
* @param obj
* @returns
*/
function validVal(obj) {
return obj==null ? '' : obj;
}
/**
* 字符串判空
* @param obj 字符串
* @returns true 表示空
*/
function isBlank(obj) {
if(typeof obj == "undefined" || obj == null || obj.trim() == "") {
return true;
}
return false;
}
//时间函数*********************************************
var oneDayTime = 24*60*60*1000;
var oneHourTime = 60*60*1000;
var oneMinuteTime = 60*1000;
/**
* 原型追加Date格式化方法
* new Date().format('yyyy-MM-dd hh:mm:ss')其他格式:yyyy年MM月dd日,MM/dd/yyyy,yyyyMMdd等
*/
Date.prototype.format = function(fmt){
var o = {
"M+" : this.getMonth()+1, //月份
"d+" : this.getDate(), //日
"h+" : this.getHours(), //小时
"m+" : this.getMinutes(), //分
"s+" : this.getSeconds(), //秒
"q+" : Math.floor((this.getMonth()+3)/3), //季度
"S" : this.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt)){
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
}
for(var k in o){
if(new RegExp("("+ k +")").test(fmt)){
fmt = fmt.replace(
RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
}
}
return fmt;
}
/**
* 获取当前时间
* @param layout 格式
* @returns
*/
function getNowDate(layout) {
return new Date().format(layout);
}
/**
* 字符串转Date对象兼容iPhone
* iPhone中的safari所支持的格式为 YYYY,MM, DD,HH,mm,ss
* iPhone中的safari无法解释 YYYY-MM-DD HH:mm:ss 或者YYYY/MM/DD HH:mm:ss这样的时间格式
* @param dateStr 必须是完整的YYYY-MM-DD HH:mm:ss 或者YYYY/MM/DD HH:mm:ss格式
* @returns
*/
function strToDate(dateStr) {
var arr = dateStr.split(/[- : \/]/);
return new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);
}
/**
* 获取指定Date对象,n天前的日期
* @param date 指定Date对象
* @param days 天数
* @returns Date字符串:标准格式yyyy-MM-dd
*/
function getPreviousDate(date, days) {
var resDateTime = date.getTime() - parseInt(days)*oneDayTime;
return new Date(resDateTime).format('yyyy-MM-dd');
}
/**
* 获取指定Date对象,n天后的日期
* @param date 指定Date对象
* @param days 天数
* @returns Date字符串:标准格式yyyy-MM-dd
*/
function getAfterDate(date, days) {
var resDateTime = date.getTime() + parseInt(days)*oneDayTime;
return new Date(resDateTime).format('yyyy-MM-dd');
}
/**
* 获取指定Date字符串,n分钟前的时间
* @param date 指定Date对象
* @param minutes 分钟数
* @returns Date字符串:标准格式yyyy-MM-dd hh:mm:ss
*/
function getPreviousMinutes(date, minutes) {
var resDateTime = date.getTime() - parseInt(minutes)*oneMinuteTime;
return new Date(resDateTime).format('yyyy-MM-dd hh:mm:ss');
}
/**
* 比较时间t1 > t2
* @param t1 Date对象
* @param t2 Date对象
* @returns t1 > t2 返回true
*/
function compareDate(t1, t2) {
return t1.getTime() > t2.getTime();
}
/**
* 比较时间字符串t1 > t2
* @param t1 Date字符串:YYYY-MM-DD HH:mm:ss 或者YYYY/MM/DD HH:mm:ss格式
* @param t2 Date
* @returns t1 > t2 返回true
*/
function compareDateStr(t1, t2) {
return strToDate(t1).getTime() > strToDate(t2).getTime();
}
/**
* 获取指定Date对象,当前周的周一和周日日期
* @param now 指定Date对象
* @returns 格式yyyy-MM-dd
*/
function getMondayAndSunday(now) {
var nowTime = now.getTime() ;
//获取星期对应的数值,0=周日 1=周一
var day = now.getDay();
if(day == 0) day = 7;
var mondayTime = nowTime - (day-1)*oneDayTime ;//周一
var sundayTime = nowTime + (7-day)*oneDayTime ;//周日
return {
monday: new Date(mondayTime).format('yyyy-MM-dd'),
sunday: new Date(sundayTime).format('yyyy-MM-dd')
};
}
/**
* 计算时间差
* @param t1 Date对象
* @param t2 Date对象
* @returns {days:1,hours:1,minutes:50,seconds:0}//天差,时差,分钟差,秒差
*/
function getTimeDifference(t1, t2) {
// var oneDayTime = 24*60*60*1000;
// var oneHourTime = 60*60*1000;
// var oneMinuteTime = 60*1000;
//Math.abs(x)取x绝对值
//Math.floor(x);取 <= x 最大整数
//计算出相差天数
var date3 = Math.abs(t2.getTime()-t1.getTime());
var days = Math.floor(date3/oneDayTime);
//计算出小时数
var leave1 = date3 % (oneDayTime);//计算天数后剩余的毫秒数
var hours = Math.floor(leave1/oneHourTime);
//计算相差分钟数
var leave2 = leave1 % oneHourTime;//计算小时数后剩余的毫秒数
var minutes = Math.floor(leave2/oneMinuteTime);
//计算相差秒数
var leave3 = leave2 % oneMinuteTime;//计算分钟数后剩余的毫秒数
var seconds = Math.round(leave3/1000);
return {
days: days,
hours: hours,
minutes: minutes,
seconds: seconds
};
}
/**
* 判断dayDate日期是否在now日期所在的周
* @param now Date对象
* @param dayDate Date对象
* @returns
*/
function isDayDateExistsNowWeek(now, dayDate) {
//获取now当前周的周一和周日日期
var obj = getMondayAndSunday(now);
//周一取00:00:00点毫秒数
var mondayTime = strToDate(obj.monday+' 00:00:00').getTime();
//周日取23:59:59毫秒数
var sundayTime = strToDate(obj.sunday+' 23:59:59').getTime();
//如果比较日期对象在周一和周日之间
var dayDateTime = dayDate.getTime();
if(mondayTime<=dayDateTime && dayDateTime<=sundayTime) {
return true;
}
return false;
}
/**
* 判断Date字符串是不是在本周
* @param dateStr Date字符串:标准格式yyyy-MM-dd HH:mm:ss
* @returns
*/
function isThisWeek(dateStr) {
return isDayDateExistsNowWeek(new Date(), strToDate(dateStr));
}
/**
* 判断Date字符串是不是在下周
* @param dateStr Date字符串:标准格式yyyy-MM-dd HH:mm:ss
* @returns
*/
function isNextWeek(dateStr) {
//获取下一周今天的日期
var resDateTime = new Date().getTime() + oneDayTime*7;
var nextDate = new Date(resDateTime);
return isDayDateExistsNowWeek(nextDate, strToDate(dateStr));
}
/**
* 获取指定Date对象的日期信息
* @param date 指定Date对象
* @returns 对象{年,月,日,时,分,秒,星期,yyyy-MM-dd,yyyy-MM-dd hh:mm:ss}
*/
function getAppointDate(date) {
var weekList = ["日", "一", "二", "三", "四", "五", "六"];
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
var week = date.getDay();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
month = month >= 10 ? month : "0" + month;
day = day >= 10 ? day : "0" + day;
seconds = seconds >= 10 ? seconds : "0" + seconds;
minutes = minutes >= 10 ? minutes : "0" + minutes;
hours = hours >= 10 ? hours : "0" + hours;
return {
year: year,
month: month,
day: day,
hours: hours,
minutes: minutes,
seconds: seconds,
week: weekList[week],//星期
currentYMD: year+'-'+month+'-'+day,//格式yyyy-MM-dd
standardDate: year+'-'+month+'-'+day+' '+hours+':'+minutes+':'+seconds//标准格式yyyy-MM-dd HH:mm:ss
};
}