一、js数据类型与四种检测方法
来源:https://www.cnblogs.com/dushao/p/5999563.html
1、数据类型
(1)5种基本数据类型:number、string、boolean、undefined、null
A、undefined
a、变量未声明。报错为"a is not defined"
console.log( value)
c、变量未赋值。默认为undefined
var value;
console.log( value)
d、对象属性不存在。默认为undefined
var obj = {}
console.log( obj.value ) // undefined
e、void(0),对后面的表达式进行求值,然后始终返回undefined
html示例,<a href="javascript:void(0)">href="#"会使页面滚动到顶部</a>
js示例,console.log(void(0) === undefined) //true
B、null
a、变量置空
var value = null;
b、普通对象判断
console.log( typeof value == "object" && value ) // 为true,则value为普通对象
(2)2种引用数据类型:
A、函数
B、对象(Array、Arguments、Object、Date、Error、RegExp)
2、arguments,实际传入的参数
(1)说明
A、它是函数内部自动生成的一个局部变量,只能在函数内部访问
B、数据类型是类数组,一种特殊对象,
C、不能直接调用数组方法,如push、forEach,
D、不能new Arguments()
(2)模拟如下
var argument = {
0: 'param0',
1: 'param1',
2: 'param2',
length: 3,
}
(3)使用
A、应通过Array.prototype.slice.call(arguments)转换为数组,
function convertToArray() {
var argsArray = [...arguments]; //展开运算符,只能展开可迭代对象
var argsArray = Array.from(arguments); //Array.from,把类数组对象和可迭代对象转换为真正的数组
var argsArray = Array.prototype.slice.call(arguments);
console.log(argsArray, Array.isArray(argsArray));
return argsArray;
}
convertToArray(1, 2, 3, "a", "b", "c");
B、Array.prototype.slice的伪定义
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length;
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
(4)arguments的数据类型检测
function fn(){
console.log( arguments );//[Arguments] { '0': 8, '1': 8, '2': 8 }
console.log( '以下用对象的方法操作arguments:');
console.log( '1:',Object.keys(arguments));//[ '0', '1', '2' ],仅包含可枚举
console.log( '2:',Object.getOwnPropertyNames(arguments));//[ '0', '1', '2', 'length', 'callee' ],还包含不可枚举
console.log( '3:',Object.values(arguments));//[ 8, 8, 8 ]
console.log( '4:',arguments.hasOwnProperty(0));//true
console.log( '5:',arguments.hasOwnProperty('0'));//true
console.log( '6:',arguments.hasOwnProperty('length'));//true,还包含不可枚举
console.log( '以下用数组的方法操作arguments:');
console.log( '7:',arguments.length );//3
console.log( '8:',Array.prototype.slice.call(arguments));//[ 8, 8, 8 ]
console.log( '以下检测arguments的数据类型:');
console.log( '9:',typeof arguments === 'object');//object
console.log( '10:',arguments instanceof Object) // true
console.log( '11:',arguments.constructor === Object) // true
console.log( '12:',Object.prototype.toString.call(arguments));//[object Arguments]
console.log( '以下检测-其它引用数据-的数据类型:');
console.log( '13:',Object.prototype.toString.call([ 8, 8, 8 ]));//[object Array]
console.log( '14:',Object.prototype.toString.call({ '0': 8, '1': 8, '2': 8 }));//[object Object]
console.log( '15:',Object.prototype.toString.call(new Object()));//[object Object]
console.log( '16:',Object.prototype.toString.call(new Date()));//[object Date]
console.log( '17:',Object.prototype.toString.call(new Error()));//[object Error]
console.log( '18:',Object.prototype.toString.call(/test/));//[object RegExp]
console.log( '19:',Object.prototype.toString.call(function(){}));//[object Function]
}
fn(8,8,8)
3、任意数据的4种检测方法
//附、被检测的数据
var myNull = null;
var myUndefined = undefined;
var myString = "string";
var myNumber = 222;
var myBoolean = true;
var myFunction = function(){};
var myArray= [1,2,3];
var myObject = {a:1};
var myRegexp = /test/;
var myDate = new Date();
var myError = new Error();
//(1)检测方法1,typeof
console.log("以下,检测方法1,typeof,返回值是布尔")
console.log(typeof myNull === 'object') // true
console.log(typeof myUndefined === 'undefined') // true
console.log( '----------------------------------------' );
console.log(typeof myString === 'string') // true
console.log(typeof myNumber === 'number') // true
console.log(typeof myBoolean === 'boolean') // true
console.log(typeof myFunction === 'function') // true
console.log(typeof myArray === 'object') // true
console.log(typeof myObject === 'object') // true
console.log(typeof myRegexp === 'object') // true
console.log(typeof myDate === 'object') // true
console.log(typeof myError === 'object') // true
console.log( '----------------------------------------' );
var obj = {
1: 'one',
}
for(var attr in obj){
console.log( typeof attr );//为什么是string,不是number
}
//(2)检测方法2,instanceof
console.log("以下,检测方法2,instanceof,返回值是布尔")
console.log(new String() instanceof String) // true
console.log(new Number() instanceof Number) // true
console.log(new Boolean() instanceof Boolean) // true
console.log( '----------------------------------------' );
console.log(myString instanceof String) // false
console.log(myNumber instanceof Number) // false
console.log(myBoolean instanceof Boolean) // false
console.log(myFunction instanceof Function) // true
console.log(myArray instanceof Array) // true
console.log(myObject instanceof Object) // true
console.log(myRegexp instanceof RegExp) // true
console.log(myDate instanceof Date) // true
console.log(myError instanceof Error) // true
//(3)检测方法3,constructor
console.log("以下,检测方法2,constructor,返回值是类")
console.log(myString.constructor === String) // true
console.log(myNumber.constructor === Number) // true
console.log(myBoolean.constructor === Boolean) // true
console.log(myFunction.constructor === Function) // true
console.log(myArray.constructor === Array) // true
console.log(myObject.constructor === Object) // true
console.log(myRegexp.constructor === RegExp) // true
console.log(myDate.constructor === Date) // true
console.log(myError.constructor === Error) // true
//(4)检测方法4,prototype
console.log("以下,检测方法4,prototype,返回值是字符串")
console.log(Object.prototype.toString.call(myNull) === "[object Null]") // true;
console.log(Object.prototype.toString.call(myUndefined) === "[object Undefined]") // true;
console.log( '----------------------------------------' );
console.log(Object.prototype.toString.call(myString) === "[object String]") // true;
console.log(Object.prototype.toString.call(myNumber) === "[object Number]") // true;
console.log(Object.prototype.toString.call(myBoolean) === "[object Boolean]") // true;
console.log(Object.prototype.toString.call(myFunction) === "[object Function]") // true;
console.log(Object.prototype.toString.call(myArray) === "[object Array]") // true;
console.log(Object.prototype.toString.call(myObject) === "[object Object]") // true;
console.log(Object.prototype.toString.call(myRegexp) === "[object RegExp]") // true;
console.log(Object.prototype.toString.call(myDate) === "[object Date]") // true;
console.log(Object.prototype.toString.call(myError) === "[object Error]") // true;
二、数字方法(数字的方法)
1、数字转换方法(Number.prototype方法)
(1)toString(radix),将数字转换为字符串,可指定进制(2-36之间,默认十进制)
const num=10;
console.log(num.toString());//"10"(十进制)
console.log(num.toString(2));//"1010"(二进制)
console.log(num.toString(16));//"a"(十六进制)
(2)toFixed(digits),将数字转换为指定小数位数的字符串(四舍五入)。
注意:digits范围为0-20,超出则可能不准确。
const num=3.14159;
console.log(num.toFixed(2));//"3.14"
console.log(num.toFixed(0));//"3"
(3)toPrecision(precision),将数字转换为指定总位数(整数+小数)的字符串(四舍五入)。
const num=123.456;
console.log(num.toPrecision(4));//"123.5"(总位数4)
console.log(num.toPrecision(2));//"1.2e+2"(科学计数法,总位数2)
(4)toExponential(fractionDigits),将数字转换为科学计数法字符串,可指定小数位数。
const num=12345;
console.log(num.toExponential());//"1.2345e+4"
console.log(num.toExponential(2));//"1.23e+4"
2、全局数字处理函数
(1)parseInt(str,radix),解析字符串并返回整数(忽略非数字部分,支持指定进制)。
注意:radix为2-36的整数,默认10(若字符串以0x开头,默认16)。
console.log(parseInt("123"));//123
console.log(parseInt("12.34"));//12(忽略小数部分)
console.log(parseInt("11",2));//3(二进制转十进制)
(2)parseFloat(str),解析字符串并返回浮点数(支持小数,忽略后续非数字部分)。
console.log(parseFloat("3.14"));//3.14
console.log(parseFloat("123abc"));//123
(3)Number(value),将任意值转换为数字(失败返回NaN)。
console.log(Number("123"));//123
console.log(Number("12.3"));//12.3
console.log(Number("abc"));//NaN
(4)isNaN(value),判断值是否为NaN(注意:NaN是唯一不等于自身的值)。
console.log(isNaN(NaN));//true
console.log(isNaN(123));//false
console.log(isNaN("123"));//false(字符串会先转换为数字)
(5)isFinite(value),判断值是否为有限数字(非Infinity、-Infinity或NaN)。
console.log(isFinite(123));//true
console.log(isFinite(Infinity));//false
console.log(isFinite("123"));//true(字符串会先转换为数字)
(6)isInteger(value),判断值是否为整数(ES6新增)。
console.log(Number.isInteger(123));//true
console.log(Number.isInteger(123.0));//true(123.0本质是整数)
console.log(Number.isInteger(123.45));//false
(7)isSafeInteger(value),判断值是否为“安全整数”(范围:-(2^53-1)到2^53-1,ES6新增)。
console.log(Number.isSafeInteger(253));//false(超出安全范围)
console.log(Number.isSafeInteger(253-1));//true
3、数学计算函数(Math对象方法)
(1)Math.abs(x):返回x的绝对值
Math.abs(-5)→5
(2)Math.ceil(x):向上取整(返回大于等于x的最小整数)
Math.ceil(3.1)→4
(3)Math.floor(x):向下取整(返回小于等于x的最大整数)
Math.floor(3.9)→3
(4)Math.round(x):四舍五入取整
Math.round(3.5)→4,Math.round(3.4)→3
(5)Math.max(...values):返回一组数中的最大值
Math.max(1,3,5)→5
(6)Math.min(...values):返回一组数中的最小值
Math.min(1,3,5)→1
(7)Math.random():返回[0,1)之间的随机浮点数
Math.random()→0.783(随机值)
(8)Math.pow(base,exponent):返回base的exponent次幂(base^exponent)
Math.pow(2,3)→8
(9)Math.sqrt(x):返回x的平方根
Math.sqrt(16)→4
(10)Math.PI:常量,表示圆周率(约3.14159)
Math.PI→3.141592653589793
4、整数范围验证方法封装,验证一个数是不是指定范围内的“整数”,且多位数的首位数不能为0
/**
*验证一个值是否为指定范围内的整数,且多位数首位数不为0
*@param{*}value-待验证的值(可能是数字、字符串等类型)
*@param{number}min-范围的最小值(包含min,必须是整数)
*@param{number}max-范围的最大值(包含max,必须是整数,且max>min)
*@returns{boolean}验证通过返回true,否则返回false
*/
functionisValidIntegerInRange(value, min, max) {
//1.先验证min和max是否为有效整数,且max>min(避免传入非法范围)
if (!Number.isInteger(min) || !Number.isInteger(max) || max <= min) {
console.error("范围参数错误:min和max必须是整数,且max>min");
returnfalse;
}
//2.验证待验证值是否为整数(排除小数、字符串等非整数类型)
//先尝试将value转为数字,若转换失败(如NaN),直接返回false
const num = Number(value);
if (!Number.isInteger(num)) {
returnfalse;
}
//3.验证数字是否在[min,max]范围内
if (num < min || num > max) {
returnfalse;
}
//4.验证多位数的首位数是否不为0(1位数无需验证,因0~9首位数就是自身)
if (num >= 10 || num <= -10) { //绝对值>=10即为多位数
const numStr = String(Math.abs(num)); //转绝对值字符串,避免负号影响首字符判断
if (numStr[0] === "0") { //首字符为0则无效
returnfalse;
}
}
//所有条件均满足,返回true
returntrue;
}
//----------------------使用示例----------------------
//示例1:验证15是否在[1,20]范围内(有效)
console.log(isValidIntegerInRange(15,1,20));//true
//示例2:验证"08"是否在[1,10]范围内("08"转数字为8,但多位数首为0,无效)
console.log(isValidIntegerInRange("08",1,10));//false
//示例3:验证3.5是否在[1,5]范围内(小数,无效)
console.log(isValidIntegerInRange(3.5,1,5));//false
//示例4:验证-12是否在[-20,-5]范围内(多位数,首为1非0,有效)
console.log(isValidIntegerInRange(-12,-20,-5));//true
//示例5:验证0是否在[0,0]范围内(1位数,有效)
console.log(isValidIntegerInRange(0,0,0));//true
//示例6:验证25是否在[30,50]范围内(超出范围,无效)
console.log(isValidIntegerInRange(25,30,50));//false
//示例7:范围参数错误(max<=min,返回false并报错)
console.log(isValidIntegerInRange(10,15,5));//false(控制台输出错误提示)
5、小数相加
(1)现象,console.log( 0.1+0.2 ); //0.30000000000000004,3和4之间有15个0
说明,参与运算的两个小数,都是分母不是2的整数幂的分数
另外,整数部分较大的小数,也会出现这个问题 //比如console.log(2**53 + 0.1); //2**53意为2的53次方
(2)原因
A、JavaScript采用64位双精度浮点数
B、计算机使用IEEE-754标准的二进制浮点数表示法
C、有些小数在二进制中是无限循环的,就像十进制中的1/3一样
D、有些小数指的是,分母不是2的整数幂的分数,比如0.1,0.2,0.3...
E、2的整数幂指的是,2、4、8、16、32...
(3)解决
A、放大为整数运算,console.log((0.1*10+0.2*10)/10); //0.3
B、使用toFixed()控制显示位数,console.log((0.1+0.2).toFixed(1)); //"0.3",注意返回的是字符串
(4)如何验证某个小数是否安全?
A、用toString(2),查看二进制表示,若出现无限循环则可能有问题
B、console.log((0.1).toString(2))
三、字符串方法(字符串的方法)!!!
(1)数组也有的方法,如concat、includes(存在性判断,ES6新增)、indexOf(位置获取)、length(属性)、slice
(2)参数可以是正则,match()、matchAll()、replace()、replaceAll()、split()、search()
(3)JS字符串为不可变类型,所有字符串方法均不修改原字符串。返回值类型不同
(4)字符串和数组的循环遍历都可以用,for(通过索引访问,可提前结束)、for...of(直接遍历字符,可提前结束)、for...in(主用遍历对象)
(5)break提前结束循环遍历、continue跳过本次循环遍历
1、截取与分割
(1)slice(start,end)
A、作用:从字符串的指定索引范围截取部分字符,生成并返回新的子字符串(用于精准截取字符串片段,支持从末尾反向定位)。
B、参数:两个可选参数,均为数字类型:
start:起始索引(可选,默认值为0)
若为负数,从字符串末尾开始计算(如-2表示倒数第二个字符);
若start超出字符串长度,返回空字符串
end:结束索引(可选,默认值为字符串长度)
若为负数,从字符串末尾开始计算;截取范围为[start,end),即包含start对应的字符,不包含end对应的字符;
若end<=start,返回空字符串
C、返回值:新的子字符串,内容为原字符串中start到end(不包含end)之间的字符;若不符合截取条件,返回空字符串
(2)substring(start,end)
A、作用:从字符串的指定索引范围截取部分字符,生成并返回新的子字符串(功能与slice类似,但不支持负数索引,且会自动调整索引顺序)
B、参数:两个可选参数,均为非负数字类型(若传入负数,会自动转为0):
start:起始索引(可选,默认值为0)
end:结束索引(可选,默认值为字符串长度)
若start>end,方法会自动交换两者位置(如substring(5,2)等同于substring(2,5));截取范围同样为[start,end)
C、返回值:新的子字符串,内容为原字符串中调整后start到end(不包含end)之间的字符;若不符合截取条件,返回空字符串
(3)substr(start,length)
A、作用:从字符串的指定起始索引开始,截取指定长度的字符,生成并返回新的子字符串
注意:该方法已被部分浏览器标记为“不推荐使用”,建议优先使用slice
B、参数:
start:起始索引(必需)。若为负数,从字符串末尾开始计算(如-3表示从倒数第三个字符开始)
length:可选参数,指定要截取的字符个数(默认值为“从start到字符串末尾的所有字符”);若为负数或0,返回空字符串
C、返回值:新的子字符串,内容为原字符串中从start开始、长度为length的字符;若不符合截取条件,返回空字符串
(4)split(separator,limit)
A、作用:根据指定的分隔符,将字符串拆分为多个子字符串,最终组成一个数组,用于“字符串转数组”
B、参数:
separator:必需参数,分隔符(可传入字符串或正则表达式)
若为''(空字符串),会将字符串拆分为单个字符的数组;
若分隔符不在原字符串中,返回包含原字符串的单元素数组
limit:可选参数,非负整数,指定数组的最大长度
若设置该参数,拆分后数组长度不会超过limit;
若limit为0,返回空数组
C、返回值:一个数组,数组元素为拆分后的子字符串;若limit生效,数组长度受限于limit
D、正则示例:"a1b2c3d4e5".split(/\d/, 3); //["a","b","c"]
2、查找与判断
(5)includes(substring)
A、作用:判断原字符串是否包含指定的子字符串,返回布尔值,用于“子串存在性判断”
B、参数:
substring:必需参数,要查找的子字符串(若为''空字符串,始终返回true)
position:可选参数,非负整数,指定从原字符串的哪个索引开始查找(默认值为0);若position大于字符串长度,返回false
C、返回值:布尔值。若原字符串包含指定子字符串(从position开始查找),返回true;否则返回false
(6)indexOf(substring)/lastIndexOf(substring)
A、作用:
indexOf(substring):从原字符串的开头(索引0)开始查找指定子字符串,返回其首次出现的起始索引;若不存在,返回-1
lastIndexOf(substring):从原字符串的末尾(最后一个字符)开始查找指定子字符串,返回其最后一次出现的起始索引;若不存在,返回-1
B、参数:
substring:必需参数,要查找的子字符串(若为''空字符串,indexOf返回0,lastIndexOf返回字符串长度)
position:可选参数,非负整数。
indexOf中表示“从该索引开始向后查找”(默认0);
lastIndexOf中表示“从该索引开始向前查找”(默认字符串长度);
若position超出字符串范围,按边界值处理(如indexOf中position过大则返回-1)
C、返回值:整数。找到子字符串则返回其起始索引,未找到则返回-1
(7)search(separator)
A、作用:在字符串中搜索与指定正则表达式匹配的第一个子串,并返回该子串的起始索引;
若未找到匹配,则返回-1。主要用于快速定位字符串中符合正则规则的内容的首次出现位置。
B、参数:separator:可为正则表达式对象(RegExp)或字符串(会自动转换为正则表达式,不包含修饰符)
若为字符串,会被当作正则模式处理,仅查找首次匹配的位置
C、返回值:数字类型
若找到匹配的子串,返回该子串的起始索引(从0开始)
若未找到任何匹配的子串,返回-1
D、正则示例:"helloWorld".search(/[A-Z]/);//5
(8)startsWith(substring)
A、作用:判断原字符串是否以指定的子字符串开头,返回布尔值(用于“字符串前缀判断”,如验证URL协议、文件后缀等场景)
B、参数:
substring:必需参数,要判断的前缀子字符串(若为''空字符串,始终返回true)
position:可选参数,非负整数,指定将原字符串的“前position个字符”视为判断对象(默认值为0,即判断整个字符串的开头)
若position大于字符串长度,返回false
C、返回值:布尔值。若原字符串(或指定position范围内的片段)以子字符串开头,返回true;否则返回false
(9)endsWith(substring)
A、作用:判断原字符串是否以指定的子字符串结尾,返回布尔值(用于“字符串后缀判断”,如验证文件格式、邮箱域名等场景)
B、参数:
substring:必需参数,要判断的后缀子字符串(若为''空字符串,始终返回true)
length:可选参数,非负整数,指定将原字符串的“前length个字符”视为判断对象(默认值为字符串长度,即判断整个字符串的结尾);
若length为0,仅当substring为''时返回true
C、返回值:布尔值。若原字符串(或指定length范围内的片段)以子字符串结尾,返回true;否则返回false
(10)padStart(targetLength,padString)!!!
A、作用:用指定的字符串填充原字符串的开头,直到原字符串达到指定的长度,返回填充后的新字符串
B、参数:
targetLength:必需参数,非负整数,指定填充后字符串的目标长度。若该值小于或等于原字符串的长度,则直接返回原字符串
padString:可选参数,用于填充的字符串(默认值为' '空格)。若填充字符串过长,会截取其前部分以满足目标长度
C、返回值:字符串。经过填充后达到目标长度的新字符串,原字符串不变
D、示例:用于格式化字符串长度,如统一数字位数、补全日期格式等场景,console.log( String(1).padStart(2, '0') );
(11)padEnd(targetLength,padString)
A、作用:用指定的字符串填充原字符串的结尾,直到原字符串达到指定的长度,返回填充后的新字符串
B、参数:
targetLength:必需参数,非负整数,指定填充后字符串的目标长度。若该值小于或等于原字符串的长度,则直接返回原字符串
padString:可选参数,用于填充的字符串(默认值为' '空格)。若填充字符串过长,会截取其前部分以满足目标长度
C、返回值:字符串。经过填充后达到目标长度的新字符串,原字符串不变
D、示例:用于格式化字符串长度,如对齐文本、补全编号等场景,console.log( "2025-07".padStart(7+8," ").padEnd(7+16," ") );
(12)match(regexp)
A、作用:根据指定的正则表达式,在原字符串中匹配符合规则的子字符串,返回匹配结果数组
B、参数:必需参数,可为正则表达式对象(RegExp)或字符串
若为字符串,会自动转为正则表达式,且不包含修饰符,如'abc'等同于/abc/
若正则表达式带有g(全局匹配)修饰符,会匹配所有符合规则的子串;若无g修饰符,仅匹配第一个符合规则的子串
C、返回值:
若有匹配结果:
无g修饰符时,返回数组(第0项为匹配的子串,后续项为正则捕获组内容,数组还包含index(匹配起始索引)和input(原字符串)属性);
有g修饰符时,返回数组(包含所有匹配子串,无捕获组和额外属性)
若无匹配结果:返回null
(13)matchAll (regexp)
A、作用:在原字符串中匹配所有符合正则表达式规则的子字符串
B、参数:必需参数,且必须是正则表达式对象(RegExp),不可为字符串,必须带有g(全局匹配)修饰符
C、返回值:
若有匹配结果:返回RegExpStringIterator类型的迭代器,迭代器的每一项为一个匹配结果数组
结构与match()无g修饰符时的返回数组一致,
第0项为匹配子串,
后续项为捕获组内容,包含index(匹配起始索引)和input(原字符串)属性
若正则有命名捕获组,还包含groups属性
若无匹配结果:返回的迭代器为空,遍历后无任何内容(不会返回null)
(14)localeCompare(targetStr,locales,options)
A、作用:
按照指定的语言环境(或默认环境)排序规则,比较当前字符串与目标字符串的顺序关系,
用于实现符合本地化习惯的字符串排序(如多语言环境下的字母、汉字、数字等排序)
B、参数:
targetStr:必需参数,字符串类型,指要与当前字符串进行比较的目标字符串
locales:可选参数,字符串或字符串数组类型,用于指定语言环境,如"zh-CN"表示中文简体、"en-US"表示美式英语
C、返回值:
-1,当前字符串在目标字符串之前
0,两个字符串按排序规则相等
1,当前字符串在目标字符串之后
D、按数字或字典序排序,字典序其实也是数字
E、示例,!!!
//字符串的localeCompare方法判断位置,数组的sort方法调整位置
//下例,如果在Unicode编码中a在b前,那么参数返回值将小于0,sort方法根据小于0,实现参数在前,数组项在前
const fruits = ['d', 'a', 'c', 'b'];
const sortedFruits = fruits.sort((a, b) => a.localeCompare(b));
3、转换与修改
(13)toUpperCase()
A、作用:将原字符串中的所有小写英文字母转换为大写英文字母,生成并返回新字符串
B、参数:无参数
C、返回值:新字符串,内容为原字符串所有小写字母转为大写后的结果;非英文字母字符保持不变
D、是否改变原字符串:否
(14)toLowerCase()
A、作用:将原字符串中的所有大写英文字母转换为小写英文字母,生成并返回新字符串(功能与toUpperCase相反,用途类似)
B、参数:无参数
C、返回值:新字符串,内容为原字符串所有大写字母转为小写后的结果;非英文字母字符保持不变
D、是否改变原字符串:否
(15)trim()
A、作用:去除原字符串开头和结尾的空白字符(包括空格、制表符\t、换行符\n、回车符\r等),生成并返回新字符串
B、参数:无参数
C、返回值:新字符串,内容为原字符串去除首尾空白后的结果;字符串中间的空白字符保持不变
D、是否改变原字符串:否。(扩展:trimStart()仅去除开头空白,trimEnd()仅去除结尾空白,用法与trim()一致)
下列说法和示例对吗
(16)replace(regexp, replacement)
A、作用:根据指定的正则表达式或字符串,在原字符串中匹配目标子串,并将其替换为指定内容,生成并返回新字符串
B、参数:
regexp:第一个参数,可为正则表达式对象(RegExp)或字符串
若为字符串,仅替换第一个匹配的子串
若为不带g修饰符的正则,仅替换第一个匹配的子串
若为带g修饰符的正则,替换所有匹配的子串
replacement:第二个参数,可为字符串或函数
若为字符串,可使用特殊占位符,如
$&,匹配的子串,"abc".replace(/b/,"[$&]") →"a[b]c"
$1,第一个捕获组内容,"2024-05-20".replace(/(\d{4})-(\d{2})-(\d{2})/,"$2/$3/$1") →"05/20/2024"
若为函数,
参数依次为“匹配的子串、捕获组1、捕获组2...、匹配起始索引、原字符串、命名捕获组对象”
返回值将作为替换内容
C、返回值:
新字符串,内容为原字符串完成替换后的结果
若无匹配子串,返回与原字符串相同的新字符串
(17)replaceAll(searchValue, replacement)
A、作用:在原字符串中匹配所有符合规则的目标子串(正则需带g修饰符,字符串直接全匹配),并将其统一替换为指定内容,生成并返回新字符串
B、参数:
searchValue:第一个参数,可为正则表达式对象(RegExp)或字符串
若为字符串,替换所有匹配的子串
若为正则,必须带g修饰符,替换所有匹配的子串
replacement:第二个参数,可为字符串或函数
若为字符串,可使用特殊占位符,如
$&,匹配的子串,
"abcb".replaceAll("b", "[$&]")//"a[b]c[b]";
"abcb".replaceAll(/b/g, "[$&]")//"a[b]c[b]"
$1,第一个捕获组内容,
"2024-05-20 2024-06-21".replaceAll(/(\d{4})-(\d{2})-(\d{2})/g, "$2/$3/$1") //"05/20/2024 06/21/2024"
若为函数,
参数依次为“匹配的子串、捕获组1、捕获组2...、匹配起始索引、原字符串、命名捕获组对象”
返回值将作为替换内容
C、返回值:
新字符串,内容为原字符串完成所有匹配子串替换后的结果
若无任何匹配子串,返回与原字符串完全相同的新字符串
(18)repeat(n)
A、作用:将原字符串重复指定的次数,生成并返回由重复结果拼接而成的新字符串
B、参数:必需参数n,为非负整数
若n为0,返回空字符串
若n为小数,会自动向下取整(如3.9等同于3)
若n为负数或Infinity,会抛出RangeError错误
C、返回值:新字符串,内容为原字符串重复n次后的拼接结果;若n=0,返回空字符串
D、是否改变原字符串:否
4、其他常用方法
(19)concat(str1,str2)
A、作用:将原字符串与一个或多个指定字符串拼接,生成并返回新的拼接字符串
B、参数:可选参数,
可传入一个或多个字符串(如concat(str1,str2,str3));
若传入非字符串参数,会自动转为字符串后再拼接。
C、返回值:新字符串,内容为原字符串依次拼接所有参数后的结果。
(20)charAt(index)
A、作用:获取原字符串中指定索引位置对应的字符,返回该字符
B、参数:必需参数index,为非负整数。
若index大于等于字符串长度或小于0,返回空字符串;
若index为小数,会自动向下取整(如2.9等同于2)。
C、返回值:字符串,内容为原字符串index位置的字符;若索引无效,返回空字符串
(21)charCodeAt(index)
A、作用:获取原字符串中指定索引位置字符的Unicode编码(十进制数),返回该编码值
B、参数:必需参数index,规则与charAt(index)一致(索引无效时,返回NaN)。
C、返回值:数字,为指定索引字符的Unicode编码;若索引无效,返回NaN。
(22)padStart(length,padStr)/padEnd(length,padStr)
A、作用:
padStart(length,padStr):在原字符串的开头填充指定字符,使填充后的字符串总长度达到length,生成并返回新字符串
padEnd(length,padStr):在原字符串的结尾填充指定字符,使填充后的字符串总长度达到length,生成并返回新字符串
B、参数:
length:必需参数,非负整数,指定补全后字符串的总长度。若length小于等于原字符串长度,不进行填充,直接返回原字符串的副本。
padStr:可选参数,用于填充的字符串(默认值为空格'')。若padStr长度大于需要填充的字符数,会截取padStr的前N个字符(N为需要填充的数量)。
C、返回值:新字符串,内容为原字符串开头/结尾填充padStr后、总长度为length的结果;若无需填充,返回与原字符串相同的新字符串
5、字符串常用判断
(1)为空的判断方法
A、if(!str.trim().length)//trim,修剪
B、if(/^\s*$/.test(str))//只有0到多个空格时,为true
(2)含有“某个字符”的判断方法,
A、if(str.indexOf(item) != -1)
(3)获取item的位置,str.indexOf(item)
(4)获取index的项
A、str.charAt(index)
B、str[index]
(5)遍历的方法,for,for…in,for…of,
var str = 'abc';
for (var i = 0; i < str.length; i++) {//可以没有var
console.log( 'for循环', str[i] );
}
for(var index in str){//可以没有var
console.log( 'for-in循环', index,str[index] );
}
for(var item of str){//可以没有var
console.log( 'for-of循环', item );
}
6、字符串的匹配工具—正则(元字符、修饰符、实例获取、方法、用法)
(1)元字符
A、\w:匹配数字、字母、下划线
B、\W:匹配非数字、字母、下划线
C、\n:匹配换行符
D、.:匹配非换行符
E、\s:匹配空格
F、\S:匹配非空格
G、^:匹配输入字符串的开始位置;在方括号中使用时,表示排除方括号中的所有字符
H、$:匹配输入字符串的结尾位置
I、*:匹配前面的子表达式0-n次
J、+:匹配前面的子表达式1-n次
K、?:匹配前面的子表达式0或1次
L、\r:匹配回车
M、[]:匹配方括号内任意一个字符,如[abc]、[a-z]、[0-9]
N、正则元字符的使用:MAC
varMACMatch=/^[A-Fa-f0-9]{2}(:[A-Fa-f0-9]{2}){5}$|^[A-Fa-f0-9]{2}(-[A-Fa-f0-9]{2}){5}$/,
(2)修饰符
A、g,使用全局匹配
B、i,忽略大小写(3)
(3)实例获取
A、console.log(/ab+c/i);///ab+c/i
B、console.log(newRegExp("ab+c","i"));///ab+c/i
C、console.log(newRegExp(/ab+c/,"i"));///ab+c/i
(4)方法
A、test()
a、用途:检测字符串是否匹配正则表达式,返回布尔值用于判断“是否存在匹配”
b、参数:仅一个参数,为string类型,即需要检测的目标字符串
c、返回值:boolean类型,若字符串中存在与正则匹配的内容则返回true,否则返回false
d、示例:/^1[3-9]\d{9}$/.test("13812345678")//true
B、exec()
a、用途:在字符串中执行正则匹配,可获取匹配结果的详细信息(包括匹配内容、捕获组、匹配位置等)
若正则开启全局模式(g修饰符),多次调用可依次获取所有匹配结果
b、参数:仅一个参数,为string类型,即需要匹配的目标字符串
c、返回值:
匹配成功时,返回Array类型数组
第0项,为完整匹配内容,
第1~n项,为对应捕获组内容,同时数组包含index(匹配起始位置)、input(原目标字符串)、groups(命名捕获组对象,无则为undefined)
匹配失败时,返回null
d、示例:/(\w+)@(\w+)\.(\w+)/.exec("我的邮箱是test@example.com,备用邮箱是abc@domain.cn");
(5)用法-解析URL
function hashA(url) {
var reg = /#([^#&=?]+)/;
if (reg.test(url)) {
return reg.exec(url)[1];
}
}
function queryUrlParam1(url) {
var obj = {};
var reg1 = /([^?=&#]+)=([^?=&#]+)/g;
var reg2 = /#([^?=&#]+)/;
url.replace(reg1, function(keyValue, key, value) {
obj[key] = value;
});
if (reg2.test(url)) {
obj['HASH'] = reg2.exec(url)[1];
}
return obj;
}
function queryUrlParam2(url) {
var obj = {};
var askText = '';
var hashText = '';
var askIndex = url.indexOf('?') === -1 ? url.length : url.indexOf('?');
var hashIndex = url.indexOf('#') === -1 ? url.length : url.indexOf('#');
if (askIndex < hashIndex) {
askText = url.substring(askIndex + 1, hashIndex);
hashText = url.substring(hashIndex + 1);
} else {
askText = url.substring(askIndex + 1);
hashText = url.substring(hashIndex + 1, askIndex);
}
if (askText) {
askText.split('&')
.forEach(function(item) {
let [key, value] = item.split('=');
obj[key] = value;
});
}
if (hashText) obj['HASH'] = hashText;
return obj;
};
var str = "https://www.baidu.com/newspage/data/landingsuper?AAA=1111&BBB=222&CCC=333#1234"
console.log(hashA(str));
console.log(queryUrlParam1(str));
console.log(queryUrlParam2(str));
(6)用法-其它
A、替换特定字符
var ary=["零","一","二","三","四","五","六","七","八","九"];
var str="今年是2017年";
var result=str.replace(/\d/g,function(value){
returnary[value]
});
console.log(result);
B、择出汉字
var str='<imgsrc="haha.png"alt="你的朋友"/>';
var reg=/alt="(.+)"/;
console.log(reg.exec(str)[1]);
7、字符串里字符重复次数
(1)对象法:把一个字母作为对象的属性名,字母出现的次数作为属性值;进而比较属性值的大小。
var str = 'SSSadsdccCCCAdkdkkkkDccdddaaaccCCsSSSSSs';
function maxstr(str) {
var obj = {};
var maxNum = 0;
var maxVal = "";
for (var i = 0; i < str.length; i++) {
var strNum = str.charAt(i)
.toLowerCase();
if (obj[strNum]) {
obj[strNum]++;
} else {
obj[strNum] = 1;
}
}
for (var attr in obj) {
if (obj[attr] > maxNum) {
maxNum = obj[attr];
maxVal = attr;
}
elseif(obj[attr] == maxNum) {
maxVal += attr
}
}
return "出现次数最多的字母是:" + maxVal + ";次数是:" + maxNum
}
var valNum = maxstr(str);
console.log(valNum);
(2)排序法:先对它们进行排序,再取出小分组和小分组被匹配的次数。
var str = 'SS张SadsdccCCC四Adkdkk张kkDccdddaa三acc四CCsS李SSSSs';
function maxstr(str) {
var maxNum = 0;
var maxVal = "";
str = str.split('')
.sort(function(one, two) {
return one.localeCompare(two)
})
.join('');
console.log("排序后的字符串是:" + str);
//下面正则的意思是:"(\w)"字符、"\1"第1个括号、"+"1次到多次、"g全局"、"i"不区分大小写
str.replace(/(\w)\1+/gi, function(bigReg, item) {
if (bigReg.length > maxNum) {
maxNum = bigReg.length;
maxVal = item;
}
elseif(bigReg.length == maxNum) {
maxVal += item;
}
});
return "出现次数最多的字母是:" + maxVal + ",次数" + maxNum;
}
var valNum = maxstr(str);
console.log(valNum);
8、计算任意字符串的宽度
(1)说明
A、半角空格(英文符号)\u0020,代码中常用的;
B、全角空格(中文符号)\u3000,中文文章中使用;
C、英文等宽、中文2倍英文宽的字体有:"宋体"、"黑体"、"楷体"
D、英文等宽(不含中文)的字体有:"Consolas"、"Courier"、"CourierNew"
E、根据不同字体获取字符串宽度
(2)方法
function getTextWidth(fontSize, fontFamily, innerText) {
const span = document.createElement('span');
// 使用 cssText 合并所有内联样式(注意样式属性值需用引号包裹,避免语法错误)
span.style.cssText = `
position: absolute;
visibility: hidden;
white-space: nowrap;
font-weight: normal;
font-size: ${fontSize};
font-family: ${fontFamily};
`;
span.textContent = innerText;
document.body.appendChild(span);
// 获取元素实际宽度(getBoundingClientRect() 需元素挂载到 DOM 后才有效)
const width = span.getBoundingClientRect().width;
document.body.removeChild(span);
return width;
}
四、数组方法(数组的方法)!!!
(1)字符串也有的方法,如concat、includes(存在性判断,ES6新增)、indexOf(位置获取)、length(属性)、slice
(2)参数不可以是正则
(3)JS数组为可变类型,有的数组方法不修改原数组,有的数组方法修改原数组。返回值类型不同
(4)字符串和数组的循环遍历都可以用,for(通过索引访问,可提前结束)、for...of(直接遍历字符,可提前结束)、for...in(主用遍历对象)
(5)break提前结束循环遍历、continue跳过本次循环遍历
1、改变原数组
(1)push(element1,...,elementN)
A、作用:向数组的末尾添加一个或多个元素
B、参数:element1,...,elementN,即要添加到数组末尾的一个或多个元素
C、返回值:添加元素后数组的新长度(一个非负整数)
(2)pop()
A、作用:删除数组的最后一个元素
B、参数:无参数
C、返回值:被删除的那个元素;若数组为空,则返回undefined
(3)unshift(element1,...,elementN)
A、作用:向数组的开头添加一个或多个元素
B、参数:element1,...,elementN,即要添加到数组开头的一个或多个元素
C、返回值:添加元素后数组的新长度(一个非负整数)
(4)shift()
A、作用:删除数组的第一个元素
B、参数:无参数
C、返回值:被删除的那个元素;若数组为空,则返回undefined
(5)splice(start,deleteCount,item1,...)
A、作用:从数组的指定位置删除元素、添加元素,或同时进行删除和添加操作
B、参数:
start:必需,指定操作的起始索引(若为负数,会从数组末尾开始计算,如-1表示最后一个元素)
deleteCount:必需,指定要删除的元素个数(若为0或负数,则不删除元素)
item1,...:可选,要添加到数组中的一个或多个元素(若不指定,则仅执行删除操作)
C、返回值:一个包含被删除元素的数组;若未删除元素,则返回空数组
(6)sort((a,b)=>{})
A、作用:对数组元素进行排序(默认按“字符串Unicode编码”排序,可通过自定义回调函数指定排序规则)
B、参数:可选参数
若不指定回调函数:先把数组项转为字符串,再按Unicode编码从小到大排序
若指定回调函数:a和b分别代表数组中相邻的两个元素,回调函数返回值决定排序位置
返回值<0,a排在b前面
返回值>0,b排在a前面
返回值=0,a和b位置不变
C、返回值:排序后的原数组(返回的是修改后的原数组本身,而非新数组)
D、示例,!!!
//字符串的localeCompare方法判断位置,数组的sort方法调整位置
//下例,如果在Unicode编码中a在b前,那么参数返回值将小于0,sort方法根据小于0,实现参数在前,数组项在前
const fruits = ['d', 'a', 'c', 'b'];
const sortedFruits = fruits.sort((a, b) => a.localeCompare(b));
(7)reverse()
A、作用:将数组的元素顺序反转(如[1,2,3]变为[3,2,1])
B、参数:无参数
C、返回值:反转后的原数组(返回的是修改后的原数组本身)
2、不改变原数组
(8)forEach((item,index,array)=>{})
A、作用:遍历数组的每个元素,并对每个元素执行指定的回调函数
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}:
item:回调函数的第一个参数,当前遍历到的数组元素
index:回调函数的第二个参数(可选),当前遍历元素的索引
array:回调函数的第三个参数(可选),调用forEach方法的原数组
C、返回值:undefined(无实际返回值)
(9)map((item)=>{})
A、作用:遍历数组的每个元素,对每个元素执行回调函数处理,并将所有回调函数的返回值组成一个新数组(用于“数组元素转换”)
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}(参数含义与forEach回调函数一致,item为必需,index和array可选)
C、返回值:一个新数组,数组中的元素是原数组每个元素经过回调函数处理后的结果(新数组长度与原数组一致)
D、是否改变原数组:否,map不修改原数组,仅返回新数组
(10)every((item)=>{})
A、作用:遍历数组的每个元素,判断所有元素是否都符合回调函数的条件(返回布尔值),若所有元素都符合则返回true,否则返回false
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}(参数含义与forEach一致),回调函数需返回布尔值
C、返回值:布尔值,
若数组中所有元素使回调函数返回true,则返回true;
若有任意一个元素使回调函数返回false,则立即停止遍历并返回false;
若数组为空,返回true(空数组默认“全满足”)
(11)some((item)=>{})
A、作用:遍历数组的每个元素,判断是否存在至少一个元素符合回调函数的条件(返回布尔值),若存在则返回true,否则返回false
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}(参数含义与forEach一致),回调函数需返回布尔值
C、返回值:布尔值,
若数组中存在至少一个元素使回调函数返回true,则立即停止遍历并返回true;
若所有元素都使回调函数返回false,则返回false;
若数组为空,返回false(空数组默认“无满足元素”)
(12)filter((item)=>{})
A、作用:遍历数组的每个元素,根据回调函数的判断条件(返回布尔值)筛选出符合条件的元素,组成一个新数组
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}(参数含义与forEach一致),回调函数需返回一个布尔值
true,表示保留元素
false,表示排除元素
C、返回值:一个新数组,包含原数组中所有使回调函数返回true的元素(新数组长度可能小于原数组);若无符合条件的元素,返回空数组
(13)includes(item)
A、作用:判断数组是否包含指定的元素,返回布尔值(用于“元素存在性判断”,支持NaN的判断,而indexOf不支持)
B、参数:两个参数,第一个为必需,第二个为可选:
item:必需参数,要判断是否存在于数组中的元素(类型不限)
fromIndex:可选参数,指定从哪个索引开始查找(默认值为0;若为负数,从数组末尾开始计算,如-2表示从倒数第二个元素开始查找)
C、返回值:布尔值,true表示数组包含该元素,false表示不包含
(14)find((item)=>{})
A、作用:遍历数组的每个元素,根据回调函数的判断条件,查找并返回第一个符合条件的元素
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}(参数含义与forEach一致),回调函数需返回布尔值(true表示找到目标元素)
C、返回值:原数组中第一个使回调函数返回true的元素;若遍历完数组无符合条件的元素,返回undefined
(15)findIndex((item)=>{})
A、作用:遍历数组的每个元素,根据回调函数的判断条件,查找并返回第一个符合条件的元素的索引(用于“查找单个符合条件元素的位置”)
B、参数:仅一个必需参数,即回调函数(item,index,array)=>{}(参数含义与forEach一致),回调函数需返回布尔值
C、返回值:原数组中第一个使回调函数返回true的元素的索引(非负整数);若无符合条件的元素,返回-1
(16)indexOf(item)/lastIndexOf(item)
A、作用:
indexOf(item):从数组的开头(索引0)开始查找指定元素,返回该元素首次出现的索引;若不存在,返回-1
lastIndexOf(item):从数组的末尾(最后一个元素)开始查找指定元素,返回该元素最后一次出现的索引;若不存在,返回-1
B、参数:两个参数,第一个为必需,第二个为可选:
item:必需参数,要查找的元素(类型不限,不支持NaN的查找,因NaN!==NaN)
fromIndex:可选参数,indexOf中表示“从该索引开始向后查找”,lastIndexOf中表示“从该索引开始向前查找”
默认值分别为0和数组长度-1;负数规则与includes一致
C、返回值:整数,若找到元素则返回其对应索引(indexOf返首次索引,lastIndexOf返最后索引),若未找到则返回-1
(17)reduce((total,item)=>{},initialValue)
A、作用:从数组的第一个元素开始(或从指定的初始值开始),对数组元素进行“累加/累积处理”,最终将数组缩减为一个单一值
B、参数:两个参数,第一个为必需回调函数,第二个为可选初始值:
回调函数(total,item,index,array)=>{}:
total:回调函数的第一个参数,“累积器”,存储上一次回调函数的返回值(或初始值initialValue)
item:回调函数的第二个参数,当前遍历到的数组元素
index(可选):当前元素的索引;
array(可选):原数组
initialValue(可选):初始值,
若指定,则total初始化为该值,从数组第一个元素开始遍历;
若不指定,则total初始化为数组第一个元素,从数组第二个元素开始遍历
C、返回值:最终的累积结果(单一值,类型由回调函数逻辑决定,如数字、字符串、对象等)
D、示例
var totalNum=ary.reduce(function(total,num) {
return total+num;
});
var totalScore = todos.reduce(function(total, item){
return item.completed ? total+item.score : total
},888);
(18)join(separator)
A、作用:将数组的所有元素拼接成一个字符串(用于“数组转字符串”)
B、参数:可选参数separator,指定拼接元素的分隔符(默认值为英文逗号,;若传入空字符串'',则元素直接拼接,无分隔符)
C、返回值:一个字符串,由数组元素按顺序拼接而成,元素间用指定的separator分隔
(19)concat(arr1,arr2)
A、作用:将调用该方法的原数组与一个或多个数组(或值)合并,组成一个新数组(用于“数组合并”)
B、参数:可选参数,可传入一个或多个参数,参数类型可以是数组或单个值(如concat(arr1,arr2,val1,val2))
C、返回值:一个新数组,包含原数组的所有元素,以及所有传入参数(数组会展开为元素,单个值直接作为元素)
(20)slice(start,end)
A、作用:从数组的指定索引范围截取元素,组成一个新数组(用于“数组截取”,不包含结束索引对应的元素)
B、参数:两个可选参数:
start:起始索引(可选,默认值为0);若为负数,从数组末尾开始计算(如-1表示最后一个元素)
end:结束索引(可选,默认值为数组长度);
若为负数,从数组末尾开始计算;截取范围为[start,end),即包含start对应的元素,不包含end对应的元素
C、返回值:一个新数组,包含原数组中从start到end(不包含end)的所有元素;若start>=end,返回空数组
3、数组常用判断
(1)为空的判断方法
A、if(!ary.length)//==长度判断法,
B、if(JSON.stringify(ary)=="[]")//==字符串判断法,空数组里有空格,字符串里没有空格,结果也是true
(2)含有“某个项”的判断方法
A、if(ary.indexOf(item) != -1)//首选方案
B、if(ary.includes(item))
(3)获取item的位置,ary.indexOf(item)
(4)获取index的项,ary[index]
(5)遍历的方法,for,for…in,for…of,另有forEach、map
var array = ['a','b'];
for (var i = 0; i < array.length; i++) {//可以没有var
console.log( 'for循环', array[i] );
}
for(var index in array){//可以没有var
console.log( 'for-in循环', index,array[index] );
}
for(var item of array){//可以没有var
console.log( 'for-of循环', item );
}
// const person = {
// name: 'Alice',
// age: 30,
// };
// const entries = Object.entries(person); //返回一个数组,其中每个元素都是一个包含对象属性名和属性值的数组
// console.log(entries);
// for (const [key, value] of entries) {
// console.log( key, value );
// }
4、数组4种去重方法
(1)新数组法:
重新构建一个新数组,遍历原数组的每一项,
如果该项在新数组的索引为-1,则把该项添加到新数组中。
var ary = [21, 32, 32, 4, 5, 61, 61, 21, 4, 5, 61];
function removeMany(ary) {
varnewAry = [];
for (vari = 0; i < ary.length; i++) {
if (newAry.indexOf(ary[i]) === -1) {
newAry[newAry.length] = ary[i];
}
}
return newAry
}
console.log(removeMany(ary))
(2)新对象法:
如果对象中没有这一项,给对象添加属性名和属性值,
如果对象中已经有了,说明是重复的,直接在数组中删除这一项;
var ary = [21, 32, 32, 4, 5, 61, 61, 21, 4, 5, 61];
function removeMany(ary) {
varobj = {};
for (vari = 0; i < ary.length; i++) {
varcur = ary[i];
if (obj[cur] === cur) { //说明重复了
ary.splice(i, 1);
i--;
} else {
obj[cur] = cur;
}
}
return ary
}
console.log(removeMany(ary))
(3)sort排序法:
先用sort方法对数组进行排序,然后拿前一项与后一项进行比较,
如果相等,则删除前一项,同时为了防止数组塌陷,下一次仍从该项开始比较。
var ary = [21, 32, 32, 4, 5, 61, 61, 21, 4, 5, 61];
function removeMany(ary) {
ary.sort(function(a, b) {
return a - b; //升序
});
for (vari = 0; i < ary.length; i++) {
if (ary[i] === ary[i + 1]) {
ary.splice(i, 1);
i--;
}
}
return ary
}
console.log(removeMany(ary))
(4)双循环法:
第一个循环,依次取出数组的每一项A;
第二个循环,从数组的A项开始,依次与A项进行比较,如果相等则删除,同时为了防止数组塌陷,下一次仍从该项开始比较。
var ary = [21, 32, 32, 4, 5, 61, 61, 21, 4, 5, 61];
function removeMany(ary) {
for (vari = 0; i < ary.length; i++) {
varcur = ary[i];
for (varj = i + 1; j < ary.length; j++) {
if (cur === ary[j]) {
ary.splice(j, 1);
j--;
}
}
}
return ary
}
console.log(removeMany(ary))
5、数组3种排序方法
(1)冒泡排序(目标:实现升序排列)
var ary = [5, 4, 3, 2, 1];
function bubbleSort(ary) {
for (vari = 0; i < ary.length - 1; i++) {
//正在进行第几次循环
for (varj = 0; j < ary.length - i - 1; j++) {
//本次循环需要执行几次
if (ary[j] > ary[j + 1]) {
vartmp = ary[j];
ary[j] = ary[j + 1];
ary[j + 1] = tmp;
}
}
console.log(ary);
}
return ary;
}
console.log(bubbleSort(ary))
(2)插入排序(目标:实现升序排列)
var ary = [50, 40, 30, 20, 10];
function insertSort(ary) {
varleft = ary.splice(0, 1);
for (vari = 0; i < ary.length; i++) {
//正在进行第几次循环
vararyAry = ary[i];
for (varj = left.length - 1; j >= 0;) {
//本次循环需要执行几次
varleftAry = left[j];
if (aryAry < leftAry) {
j--;
if (j === -1) {
left.unshift(aryAry);
}
} else {
left.splice(j + 1, 0, aryAry);
break;
}
}
}
return left;
}
console.log(insertSort(ary));
(3)快速排序(目标:实现升序排列,用到了递归)
var ary = [500, 400, 300, 200, 100];
function quickSort(ary) {
if (ary.length <= 1) {
return ary;
}
varnum = Math.floor(ary.length / 2);
varnumValue = ary.splice(num, 1)[0];
varleft = [];
varright = [];
for (vari = 0; i < ary.length; i++) {
varcur = ary[i];
if (cur < numValue) {
left.push(cur);
} else {
right.push(cur);
}
}
return quickSort(left)
.concat([numValue], quickSort(right));
}
console.log(quickSort(ary));
五、对象方法(对象的方法)
1、Object静态方法(直接通过Object调用)
(1)Object.keys()
A、用途:获取对象自身所有可枚举属性的名称,以字符串数组形式返回(不包含继承属性和Symbol属性)
B、参数:obj(必需),要获取属性名称的目标对象
C、返回值:字符串数组,包含对象自身可枚举属性的名称,顺序与for...in循环遍历顺序一致(但不遍历继承属性)
(2)Object.values()
A、用途:获取对象自身所有可枚举属性的对应值,以数组形式返回(不包含继承属性和Symbol属性对应的值)
B、参数:obj(必需),要获取属性值的目标对象
C、返回值:数组,包含对象自身可枚举属性的对应值,顺序与Object.keys()返回的属性名称顺序一致
(3)Object.entries()
A、用途:获取对象自身所有可枚举属性的「键值对数组」,每个子数组格式为[属性名,属性值](不包含继承属性和Symbol属性)
B、参数:obj(必需),要获取键值对的目标对象
C、返回值:二维数组,每个子数组对应对象的一个可枚举属性,顺序与Object.keys()一致
(4)Object.assign()
A、用途:将一个或多个「源对象」的可枚举属性复制到「目标对象」,返回合并后的目标对象(浅拷贝,即属性值为引用类型时仅复制引用)
B、参数:target(必需,目标对象)、source1,source2,...(可选,一个或多个源对象,后续源对象会覆盖前面源对象的同名属性)
C、返回值:合并后的目标对象target
(5)Object.create()
A、用途:创建一个新对象,并指定该新对象的「原型对象」和可选的「自身属性描述符」
B、参数:
proto(必需,新对象的原型对象,若为null则新对象无原型)、
propertiesObject(可选,以对象形式定义新对象的自身属性,格式需符合属性描述符规范,如{name:{value:'张三',writable:true}})
C、返回值:新创建的对象,其原型为proto,自身属性由propertiesObject定义(若提供)
(6)Object.freeze()
A、用途:冻结对象,使其成为「不可变对象」——无法添加新属性、删除现有属性、修改属性值或属性描述符
(浅冻结,若属性值为引用类型,引用类型内部仍可修改)
B、参数:obj(必需),要冻结的目标对象
C、返回值:被冻结后的原对象obj(冻结后对象的extensible、writable等描述符会被修改为不可变状态)
(7)Object.isFrozen()
A、用途:判断目标对象是否已被冻结(即是否通过Object.freeze()处理过)
B、参数:obj(必需),要检测的目标对象
C、返回值:布尔值,true表示对象已冻结,false表示未冻结(非对象类型会直接返回true,因原始值本身不可变)
(8)Object.is()
A、用途:判断两个值是否「严格相等」,修复了===运算符的两个缺陷(NaN===NaN为false,+0===-0为true)
B、参数:value1(必需,第一个要比较的值)、value2(必需,第二个要比较的值)
C、返回值:布尔值,true表示两个值严格相等(规则:NaN与自身相等、+0与-0不相等、其他情况同===),false表示不相等
(9)Object.getPrototypeOf()
A、用途:获取目标对象的「原型对象」(即[[Prototype]]内部属性的值,等同于ES5前的obj.__proto__,但更标准)
B、参数:obj(必需),要获取原型的目标对象
C、返回值:目标对象的原型对象,若对象无原型(如Object.create(null)创建的对象)则返回null
(10)Object.setPrototypeOf()
A、用途:修改目标对象的「原型对象」(即设置[[Prototype]]内部属性的值),谨慎使用(可能影响对象的继承链和性能)
B、参数:obj(必需,要修改原型的目标对象)、proto(必需,新的原型对象,可为null)
C、返回值:修改原型后的原对象obj
2、Object.prototype实例方法(所有对象都能调用)
(1)obj.toString()
A、用途:返回对象的字符串表示形式,默认返回[object类型](如{}.toString()返回"[objectObject]"),可被自定义对象重写以实现特定逻辑
B、参数:无
C、返回值:字符串,默认格式为"[object构造函数名]"(如数组[1,2].toString()返回"1,2",因数组重写了该方法)
(2)obj.valueOf()
A、用途:返回对象的原始值表示(如数字对象newNumber(123).valueOf()返回123),当对象参与原始值运算时会自动调用
B、参数:无
C、返回值:对象对应的原始值(如Date对象返回时间戳、Array对象返回自身而非原始值),若无法转换为原始值则返回对象本身
(3)obj.hasOwnProperty()
A、用途:判断对象「自身是否拥有指定属性」(不包含继承的属性,无论属性是否可枚举)
B、参数:prop(必需,要检测的属性名,可为字符串或Symbol)
C、返回值:布尔值,true表示对象自身拥有该属性,false表示属性是继承的或不存在
(4)obj.isPrototypeOf()
A、用途:判断当前对象是否是另一个对象的「原型对象」(即当前对象是否在另一个对象的原型链上)
B、参数:anotherObj(必需,要检测的目标对象,即判断当前对象是否是该对象的原型)
C、返回值:布尔值,true表示当前对象是anotherObj的原型(或在其原型链上),false表示不是
(5)obj.propertyIsEnumerable()
A、用途:判断对象「自身的指定属性是否可枚举」(不包含继承属性,仅检测自身属性的enumerable描述符)
B、参数:prop(必需,要检测的属性名,可为字符串或Symbol)
C、返回值:布尔值,true表示对象自身拥有该属性且属性可枚举,false表示属性不存在、是继承的或不可枚举
(6)obj.hasOwn()
A、用途:ES2022新增,功能与hasOwnProperty()类似,判断对象「自身是否拥有指定属性」,但更简洁且避免了hasOwnProperty被重写的风险
B、参数:prop(必需,要检测的属性名,可为字符串或Symbol)
C、返回值:布尔值,true表示对象自身拥有该属性,false表示属性是继承的或不存在
(与hasOwnProperty区别:若对象重写了hasOwnProperty,hasOwn仍能正常工作)
(7)obj.toLocaleString()
A、用途:返回对象的「本地化字符串表示」,默认调用toString(),但部分内置对象(如Date、Number、Array)重写了该方法以适配不同地区的格式(如newDate().toLocaleString()返回本地时间格式字符串)
B、参数:无默认强制参数,部分重写该方法的对象会接收本地化相关参数(如newNumber(1234).toLocaleString('zh-CN')返回"1,234")
C、返回值:本地化格式的字符串,具体格式由对象类型和地区决定
3、改变this指向的三个方法
(1)bind
A、用途:创建一个新函数,将原函数的this永久绑定到指定对象,同时可预先传入部分参数(柯里化),新函数调用时会使用绑定的this和预设参数
B、参数:
第一个参数(必需):thisArg,指定新函数中this的指向(若用new调用新函数,此参数失效)
后续参数(可选):arg1,arg2,...,预先传入的参数,新函数调用时会在实参前插入这些参数
C、返回值:返回一个新的绑定函数,该函数与原函数逻辑一致,但this指向固定,且包含预设参数
(2)call
A、用途:立即调用原函数,强制将函数执行时的this绑定到指定对象,并传入参数列表,用于临时改变this指向并执行函数
B、参数:
第一个参数(必需):thisArg,指定函数执行时this的指向(非严格模式下为null/undefined时,this指向全局对象)
后续参数(可选):arg1,arg2,...,以逗号分隔的参数列表,作为原函数的实参
C、返回值:返回原函数的执行结果(若原函数无返回值,则返回undefined)
(3)apply
A、用途:立即调用原函数,强制将函数执行时的this绑定到指定对象,并传入参数数组(或类数组对象),功能与call类似,仅参数传递方式不同
B、参数:
第一个参数(必需):thisArg,同call,指定函数执行时this的指向
第二个参数(可选):argsArray,参数数组或类数组对象(如[arg1,arg2]),数组元素作为原函数的实参
C、返回值:返回原函数的执行结果(与call一致)
(4)核心区别总结
A、调用时机:
bind返回新函数(需手动调用),
call和apply会立即执行原函数
B、参数传递:
call接收逗号分隔的参数列表,
apply接收参数数组(或类数组),
bind既可以预设参数也可在调用新函数时补充参数(预设参数在前,新参数在后)
C、this绑定:三者都能改变this指向,
bind的绑定是永久的(新函数的this无法再次修改),
call和apply的绑定仅在当前调用有效
4、对象常用判断
附、属性获取说明
A、Object.keys(仅含可枚举属性)
B、Object.getOwnPropertyNames(还含不可枚举属性)
C、Object.hasOwnProperty(还含不可枚举属性)
附、属性可枚举说明
A、for...in,遍历的属性
B、Object.keys(),访问的属性
C、描述符(enumerable)决定,默认为true
D、自身属性、原型链属性:有的可枚举,有的不可枚举
(1)为空的判断方法
A、if(!Object.keys(obj).length)//==长度判断法1/2
B、if(!Object.getOwnPropertyNames(obj).length)//==长度判断法2/2
C、if(JSON.stringify(obj)=="{}")//==字符串判断法,空对象里有空格,字符串里没有空格,结果也是true
(2)含有“某个键”的判断方法
A、if(key in obj)//------等同于if(Reflect.has(obj, name))
B、if(obj.hasOwnProperty(key))
注意,if(obj.key)不可以,因为排除了obj={ key: 0 || false || null || undefined }
(3)获取key属性项的位置
A、对象里面的项是无序的,如果有位置要求,则应该写成数组形式
(4)获取index位置的项
A、对象里面的项是无序的,如果有位置要求,则应该写成数组形式
(5)遍历的方法
A、示例
var object = {
1: 1,
'2': 2,
true: 3,
null: 4,
undefined: 5,
};
for(var key in object){
console.log( object[key], typeof key, key, );
}
Object.keys(object).forEach(key => {
console.log( object[key], typeof key, key, );
});
Object.entries(object).forEach(([key, value]) => {
console.log( value, typeof key, key, );
});
B、问题与原因
a、问题:typeof key,的结果都是string
b、原因:JS对象的属性名只能是字符串或Symbol,其他类型,引擎会隐式调用.toString()将其转换为字符串
C、解决:用Map,任意唯一键对象
const map = new Map([
[1, 2],
[1, 1], //覆盖前一个
['2', 2],
[true, 3],
[null, 4],
[undefined, 5],
]);
for (const [key, value] of map) {
console.log(value, key, typeof key);
}
5、对象相等的判断方法
// 封装一个判断两个js数据是否相等的方法
//(1)方法1
function isDeepEqualA(aaa, bbb) {
if (typeof aaa !== typeof bbb || Array.isArray(aaa) !== Array.isArray(bbb)) {
//以下,A、数据类型不同;B、数据类型相同,且1个是数组,1个不是数组(是对象)
return false;
} else if (Array.isArray(aaa)) { //以下,2个同为数组
for (let i = 0; i < aaa.length; i++) {
if (!isDeepEqualA(aaa[i], bbb[i])) {
return false;
}
}
} else if (typeof aaa === 'object' && aaa !== null && bbb !== null) { //以下,2个都为对象(都不为null)
const aaaKeys = Object.keys(aaa).sort();
const bbbKeys = Object.keys(bbb).sort();
if (JSON.stringify(aaaKeys) !== JSON.stringify(bbbKeys)) {
return false;
}
for (let key of aaaKeys) {
if (!isDeepEqualA(aaa[key], bbb[key])) {
return false;
}
}
} else { //以下,A、2个同为基本类型;B、2个同为对象,且1个为null,1个(不)为null
return aaa === bbb;
}
return true;
}
//(2)方法2
function isDeepEqualB(aaa, bbb) {
if (Object.prototype.toString.call(aaa) !== Object.prototype.toString.call(bbb)) { //以下,2个不同类型的数据
return false;
} else if (Object.prototype.toString.call(aaa) === "[object Array]") { //以下,2个同为数组类型的数据
for (let i = 0; i < aaa.length; i++) {
if (!isDeepEqualB(aaa[i], bbb[i])) {
return false;
}
}
} else if (Object.prototype.toString.call(aaa) === "[object Object]") { //以下,2个同为对象类型的数据
const aaaKeys = Object.keys(aaa).sort();
const bbbKeys = Object.keys(bbb).sort();
if (JSON.stringify(aaaKeys) !== JSON.stringify(bbbKeys)) {
return false;
}
for (let key of aaaKeys) {
if (!isDeepEqualB(aaa[key], bbb[key])) {
return false;
}
}
} else { //以下,2个同为基本类型或同为null的数据
return aaa === bbb;
}
return true;
}
//(3)数据
var flag = true;
if(flag){
console.log( '正在使用A组数据' );
var aaa = [ 0, 1, 2, 3 ];
var bbb = { 0:0, 1:1, 2:2, 3:3 };
}else{
console.log( '正在使用B组数据' );
var aaa = { a: 1, b: 'b', c: false, d: null, };
var bbb = { a: 1, b: 'b', c: false, d: null, e: undefined};
}
//(4)比较
console.log('用,isDeepEqualA,比较',isDeepEqualA(aaa, bbb)); //false
console.log('用,isDeepEqualB,比较',isDeepEqualB(aaa, bbb)); //false
6、对象浅克隆
(1)特点
A、复制对象第一层基本类型的值
B、复制对象第一层引用类型的引用地址
C、新旧对象第一层项目增减与改变都不影响对方
(2)数组的浅克隆方法
A、slice
B、concat
C、[...arr]
D、Array.from(arr)
(3)对象的浅克隆方法
A、Object.assign({}, obj)
B、{...obj}
7、对象深克隆(含递归)
//以下,定义3个深克隆方法
function deepCloneA(arrayOrObject) { //方法1,value为undefined的键值对将消失
return JSON.parse(JSON.stringify(arrayOrObject));
}
function deepCloneB(arrayOrObject) { //方法2
var target = null;
//{ }.toString.call也可以用Object.prototype.toString.call代替
if ({}.toString.call(arrayOrObject) === "[object Array]") target = [];
if ({}.toString.call(arrayOrObject) === "[object Object]") target = {};
for (var key in arrayOrObject) {
var value = arrayOrObject[key];
if ({}.toString.call(value) === "[object Array]" || {}.toString.call(value) === "[object Object]" ) {
target[key] = deepCloneB(value); //递归
} else {
target[key] = value;
}
}
return target;
}
function deepCloneC(obj) { //方法3
if (typeof obj !== 'object' || obj === null) { // 如果不是对象或者是 null,直接返回
return obj;
}
if (Array.isArray(obj)) { // 处理数组
const arrCopy = [];
for (let i = 0; i < obj.length; i++) {
arrCopy[i] = deepCloneC(obj[i]); //递归
}
return arrCopy;
}
const objCopy = {}; // 处理对象
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
objCopy[key] = deepCloneC(obj[key]);
}
}
return objCopy;
}
//以下,数据
var aaa = { a: 1, b: 'b', c: false, d: null, e: undefined};
var bbb = { a: 1, b: { c: 3 }, d: { e: [1, 2] } };
//以下,运行效果
console.log('用,deepCloneA,JSON简易克隆');
console.log(deepCloneA(aaa));
console.log(deepCloneA(bbb));
console.log('用,deepCloneB,不区分数据类型克隆');
console.log(deepCloneB(aaa));
console.log(deepCloneB(bbb));
console.log('用,deepCloneC,区分数据类型克隆');
console.log(deepCloneC(aaa));
console.log(deepCloneC(bbb));
六、两行布局
1、固定高,此增彼减;flex实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
.full {
height: 600px;
background: red;
display: flex;/* 相关代码 */
flex-direction: column;/* 相关代码 */
}
.up {
background: blue;
}
.down {
background: green;
flex: 1;/* 相关代码 */ /*height:100%;*/
}
</style>
</head>
<body>
<div class="full">
<div class="up">
<p>ABCD</p>
</div>
<div class="down">
<p>DCBA</p>
</div>
</div>
</body>
</html>
2、正好占满全屏
(1)calc实现,先上,后下左、下右
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.up {
height: 50px;
background: #BBE8F2;
width: 100%;
}
.down {
height: calc(100% - 60px);/* 相关代码 */
background: #D9C666;
margin-top: 10px;
font-size: 0;
display: flex;/* 相关代码 */
}
.left {
width: 200px;
height: 100%;
overflow: auto;
background: palevioletred;
margin-right: 10px;
font-size: 16px;
}
.right {
width: calc(100% - 210px);/* 相关代码 */
height: 100%;
overflow: auto;
background: rebeccapurple;
font-size: 16px;
}
</style>
</head>
<body>
<div class="up"></div>
<div class="down">
<div class="left">
</div>
<div class="right">
</div>
</div>
</body>
</html>
(2)flex实现,先上,后下左、下右
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.body {
display: flex;
flex-direction: column;
}
.up {
height: 50px;
background: #BBE8F2;
width: 100%;
}
.down {
flex: 1;
background: #D9C666;
font-size: 0;
display: flex;
}
.left {
width: 200px;
height: 100%;
overflow: auto;
background: rebeccapurple;
font-size: 16px;
margin-right: 10px;
}
.right {
flex: 1;
overflow: auto;
background: rebeccapurple;
font-size: 16px;
}
</style>
</head>
<body class="body">
<div class="up"></div>
<div class="down">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
七、两列布局
附、两个需求
(1)左侧固定宽、右侧占满余屏
(2)左、右自适应高
附、四个实现
(1)table
(2)flex
(3)内外补+浮动
(4)大高赋给小高
1、table
<!DOCTYPE html>
<html lang="en">
<head>
<title>两列高度自适应</title>
<style type="text/css">
* { margin: 0; padding: 0; }
</style>
</head>
<body>
<table style="width:100%">
<tr>
<td style="width:200px;background: #ddd;">
<br/>
</td>
<td style="width:calc(100% - 200px);background: #ddd;">
<br/>
<br/>
<br/>
<br/>
</td>
</tr>
</table>
<p>我是尾部,我是尾部,我是尾部,我是尾部,我是尾部,我是尾部!</p>
</body>
</html>
2、flex
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
* { margin: 0; padding: 0; }
</style>
</head>
<body>
<div style="display:flex">
<div style="width:200px;background: #ddd;margin-right: 10px;"><br/></div>
<div style="flex:1;background: #ddd;"><br/><br/><br/><br/><br/></div>
</div>
</body>
</html>
3、内外补+浮动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>两列高度自适应</title>
<style type="text/tailwindcss">
#main {
/*
创建BFC(块级格式化上下文),包含内部浮动元素的高度,防止高度塌陷。
BFC的高度计算会包含其内部浮动元素的完整高度(内容+内边距+边框)。
overflow:hidden同时隐藏超出容器的内容(包括扩展的背景区域)。
*/
overflow: hidden;
}
.both {
padding-bottom: 10000px; /* 扩展元素的背景区域(默认包含内容区和内边距) */
background: #ddd;
margin-bottom: -10000px; /*
负边距会将元素在文档流中的位置向上偏移,抵消padding-bottom增加的高度,
防止父容器被撑开。但背景色已随padding扩展,负边距不会影响背景的显示范围。
*/
}
.left {
/* 浮动元素脱离文档流并向左排列,实现左列布局。
浮动会触发BFC,但此处父容器的BFC由#main的overflow:hidden创建。 */
float: left;
width: 200px;
}
.right {
margin-left: 210px; /* 与左侧浮动元素保持10px间距,形成两列布局 */
}
</style>
</head>
<body>
<div id="main">
<div class="left both">
<p>我是左边!</p>
<p>我是左边!</p>
<p>我是左边!</p>
<p>我是左边!</p>
<p>我是左边!</p>
<p>我是左边!</p>
<p>我是左边!</p>
<p>我是左边!</p>
</div>
<div class="right both">
<p>我是右边!</p>
<p>我是右边!</p>
<p>我是右边!</p>
</div>
</div>
<p>我是尾部,我是尾部,我是尾部,我是尾部,我是尾部,我是尾部!</p>
</body>
</html>
4、大高赋给小高
(1)浮动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
#left {
float: left;
width: 200px;
background: #ddd;
}
#right {
margin-left: 210px;
background: #ddd;
}
</style>
</head>
<body>
<div>
<div id="left"><br/><br/><br/></div>
<div id="right"><br/><br/><br/><br/><br/><br/><br/></div>
</div>
<p>我是尾部,我是尾部,我是尾部,我是尾部,我是尾部,我是尾部!</p>
</body>
</html>
<script type="text/javascript">
var left = document.getElementById("left");
var right = document.getElementById("right");
var leftHeight = parseFloat(getComputedStyle(left).height);
var rightHeight = parseFloat(getComputedStyle(right).height);
var distanceHeight = leftHeight - rightHeight;
if (distanceHeight > 0) {
right.style.height = leftHeight + "px";//right.style.height =rightHeight +distanceHeight+ "px";
//right.style.height只能赋值,不能获取,所以此处用rightHeight代替right.style.height
} else {
left.style.height = rightHeight + "px";//left.style.height = leftHeight-distanceHeight + "px";
}
</script>
(2)定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>左右固定宽,中间自适应</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.left {
top: 0;
left: 0;
position: absolute;
width: 200px;
background: #ddd;
}
.right {
top: 0;
left: 210px;
right: 0;
position: absolute;
background: #ddd;
}
</style>
</head>
<body>
<div id="left" class="left"><br/><br/><br/><br/><br/><br/></div>
<div id="right" class="right"><br/></div>
</body>
</html>
<script type="text/javascript">
var left = document.getElementById("left");
var right = document.getElementById("right");
var leftHeight = parseFloat(getComputedStyle(left).height);
var rightHeight = parseFloat(getComputedStyle(right).height);
var distanceHeight = leftHeight - rightHeight;
if (distanceHeight > 0) {
right.style.height = leftHeight + "px";//right.style.height =rightHeight +distanceHeight+ "px";
//right.style.height只能赋值,不能获取,所以此处用rightHeight代替right.style.height
} else {
left.style.height = rightHeight + "px";//left.style.height = leftHeight-distanceHeight + "px";
}
</script>
5、jQuery实现多div等高(与方案4相似)
$(function() {
var maxHeight = 0;
//以下求最高的div的高度
$(".height").each(function() {
var thisHeight = $(this).innerHeight();
maxHeight = thisHeight > maxHeight ? thisHeight : maxHeight;
})
//以下将最高的div的高度赋值给每一个(需要与最高div等高的)div,
$(".height").each(function() {
var thisPadding = $(this).innerHeight() - $(this).height();
//在jQuery中,innerheight=padding+内容height
$(this).height(maxHeight - thisPadding);
})
})
八、三列布局
附、两个需求
(1)左右两侧固定宽、中间占满余屏
(2)左、中、右自适应高
附、四个实现
(1)table
(2)flex
(3)内外补+浮动
(4)大高赋给小高
1、table
<!DOCTYPE html>
<html lang="en">
<head>
<title>两列高度自适应</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<table style="width:100%">
<tr>
<td style="width:200px;background: #ddd;"><br/></td>
<td style="width:calc(100% - 400px);background: #ddd;"><br/><br/><br/><br/></td>
<td style="width:200px;background: #ddd;"><br/></td>
</tr>
</table>
<p>我是尾部,我是尾部,我是尾部,我是尾部,我是尾部,我是尾部!</p>
</body>
</html>
2、flex
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>左右固定宽,中间自适应</title>
<style>
* {
margin: 0;
padding: 0;
}
.flex {
display: flex;
}
.leftAndRight{
width: 200px;
background: #ddd;
}
.middle{
flex: 1;
margin:0 10px;
background: #ddd;
}
</style>
</head>
<body>
<div class="flex">
<div class="leftAndRight"><br/></div>
<div class="middle"><br/><br/><br/><br/></div>
<div class="leftAndRight"><br/></div>
</div>
</body>
</html>
3、内外补+浮动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>三列高度自适应</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#main {
overflow: hidden;
}
.three{
background: #ddd;
padding-bottom: 10000px;
margin-bottom: -10000px;
float: left;
}
.leftAndRight {
width: 200px;
}
.middle {
margin-left: 10px;
margin-right: 10px;
width:calc(100% - 420px)
}
</style>
</head>
<body>
<div id="main">
<div class="leftAndRight three"><br/></div>
<div class="middle three"><br/><br/><br/><br/><br/></div>
<div class="leftAndRight three"><br/></div>
</div>
<p>我是尾部,我是尾部,我是尾部,我是尾部,我是尾部,我是尾部!</p>
</body>
</html>
4、大高赋给小高
(1)浮动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>三列高度自适应</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.three{
background: #ddd;
float: left;
}
.leftAndRight {
width: 200px;
}
.middle {
margin-left: 10px;
margin-right: 10px;
width:calc(100% - 420px)
}
</style>
</head>
<body>
<div>
<div class="leftAndRight three" id="left"><br/></div>
<div class="middle three" id="middle"><br/><br/><br/><br/><br/></div>
<div class="leftAndRight three" id="right"><br/></div>
</div>
<p>我是尾部,我是尾部,我是尾部,我是尾部,我是尾部,我是尾部!</p>
</body>
</html>
<script type="text/javascript">
var left = document.getElementById("left");
var middle = document.getElementById("middle");
var right = document.getElementById("right");
var leftHeight=parseFloat(getComputedStyle(left).height);
var middleHeight=parseFloat(getComputedStyle(middle).height);
var rightHeight=parseFloat(getComputedStyle(right).height);
var maxHeight=0;
if(leftHeight-middleHeight>0){
maxHeight= leftHeight;
}else{
maxHeight= middleHeight;
}
if(rightHeight-maxHeight>0){
maxHeight= rightHeight;
}
left.style.height =maxHeight+ "px";
middle.style.height =maxHeight+ "px";
right.style.height =maxHeight+ "px";
</script>
(2)定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>左右固定宽,中间自适应</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.leftAndRight {
top: 0;
width: 200px;
position: absolute;
background: #ddd;
}
.left {
left: 0;
}
.right {
right: 0;
}
.middle {
top: 0;
left: 210px;
right: 210px;
background: #ddd;
position: absolute;
}
</style>
</head>
<body>
<div id="left" class="left leftAndRight"><br/><br/></div>
<div id="middle" class="middle"><br/><br/><br/><br/><br/><br/></div>
<div id="right" class="right leftAndRight"><br/></div>
</body>
</html>
<script type="text/javascript">
var left = document.getElementById("left");
var middle = document.getElementById("middle");
var right = document.getElementById("right");
var leftHeight=parseFloat(getComputedStyle(left).height);
var middleHeight=parseFloat(getComputedStyle(middle).height);
var rightHeight=parseFloat(getComputedStyle(right).height);
var maxHeight=0;
if(leftHeight-middleHeight>0){
maxHeight= leftHeight;
}else{
maxHeight= middleHeight;
}
if(rightHeight-maxHeight>0){
maxHeight= rightHeight;
}
left.style.height =maxHeight+ "px";
middle.style.height =maxHeight+ "px";
right.style.height =maxHeight+ "px";
console.log(maxHeight)
</script>
九、五种盒子四方居中
1、4种定位四方居中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>4种定位四方居中</title>
<style>
#mask1_1 {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
}
#content1_1{
background-color: gray;
}
#mask2_4 {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
}
#content2_2{
position: fixed;
left: 50%;/* 父级宽度的50% */
top: 50%;
transform: translate(-50%, -50%);/* 自身宽度的50% */
background-color: gray;
}
#content3_3{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: 400px;
height: 300px;
background-color: gray;
}
#content4_4{
position: fixed;
background-color: gray;
}
</style>
</head>
<body>
<div id="mask1_1"><div id="content1_1">居中一</div></div>
<!-- <div id="mask1_1"><div id="content1_1">居中一</div></div> -->
<!-- <div id="mask2_4"><div id="content2_2">居中二</div></div> -->
<!-- <div id="mask2_4"><div id="content3_3">居中三</div></div> -->
<!-- <div id="mask2_4"><div id="content4_4">居中四</div></div> -->
</body>
</html>
<script>
var oDiv = document.getElementById('content4_4');
if(oDiv){
var clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
var clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
oDiv.style.left = (clientWidth - oDiv.clientWidth) / 2 + 'px';
oDiv.style.top = (clientHeight - oDiv.clientHeight) / 2 + 'px';
}
</script>
2、1种无定位四方居中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS无定位居中</title>
<style>
.outer{
width: 1000px;
height: 500px;
background: gray;
text-align: center;/* 此处,左右居中 */
}
/* 以下,上下居中 */
.middleShow{
width: 200px;
height: 100px;
display: inline-block;
vertical-align: middle;
/* 以下,标识区域 */
background: gainsboro;
}
.middleHide{
width: 0;
height: 100%;
display: inline-block;
vertical-align: middle;
}
</style>
</head>
<body>
<div class="outer">
<div class="middleShow"></div>
<div class="middleHide"></div>
</div>
</body>
</html>
3、三种横向换行也居中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3种横向换行也居中</title>
<style>
.center{
display: flex;
flex-wrap: wrap;
flex-direction: column;
border: 1px solid green;
align-items: center;/* 独特之处 */
}
.center1{
display: flex;
flex-wrap: wrap;
flex-direction: row;
border: 1px solid green;
justify-content: center;/* 独特之处 */
}
.center2{
display: flex;
flex-wrap: wrap;
flex-direction: row;
border: 1px solid green;
justify-content: space-around;/* 独特之处 */
}
.center3{
display: flex;
flex-wrap: wrap;
flex-direction: row;
border: 1px solid green;
justify-content: space-between;/* 独特之处 */
}
.center > div,.center1 > div,.center2 > div,.center3 > div{
width: 400px;
height: 80px;
border: 1px solid red;
}
</style>
</head>
<body>
<div class="center">
<div>竖向换行也居中</div>
<div></div>
</div>
<div class="center1">
<div>横向换行也居中-1,之间无间距</div>
<div>justify-content: center</div>
</div>
<div class="center2">
<div>横向换行也居中-2,之间大间距</div>
<div>justify-content: space-around</div>
</div>
<div class="center3">
<div>横向换行也居中-3,之间超大间距</div>
<div>justify-content: space-between</div>
</div>
</body>
</html>
十、em、rem自适应
1、em示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>em示例</title>
<style>
.parent {
font-size: 30px
}
.child {
width: 40em;
height: 10em;
background: #888888;
padding: 1em;
}
</style>
</head>
<body>
<div class="parent">
<div class="child">
em的计算规则:<br>
1、用于font-size属性时,em基于父元素的字体大小<br>
2、用于其他属性,如(margin: 0.5em 0;)时,em基于当前元素自身的font-size<br>
</div>
</div>
</body>
</html>
2、rem自适应示例
(1)rem自适应示例之css版(实用程度低)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rem自适应示例之css版(实用程度低)</title>
<style>
html { font-size: 20px; }
/* :root { font-size: 20px; } */
</style>
</head>
<body>
<div style="font-size: 1.6rem">
<div style="width: 50rem;height:18rem;background: red;border:1px solid green;border-radius:10px;font-family:'楷体';padding-left:20px;">
<p>根字体的大小即1rem,用rem做单位的都是相对于根字体大小的。</p>
<p>CSS设置根字体,有2种方法,见style标签</p>
</div>
</div>
</body>
</html>
(2)rem自适应示例之js版(实用程度高)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rem自适应示例之js版(实用程度高)</title>
</head>
<body>
<div style="font-size: 16rem">
<div style="width: 500rem;height:180rem;background: red;border:1px solid green;border-radius:10px;font-family:'楷体';padding-left:20px;">
<p>根字体的大小即1rem,用rem做单位的都是相对于根字体大小的。</p>
<p>下面把1rem定义为:(屏幕宽度/设计稿的宽度)+"px"。</p>
<p>document.documentElement.style.fontSize=</p>
<p>document.documentElement.clientWidth/750+"px";</p>
</div>
</div>
</body>
</html>
<script>
var designWidth = 1000 ;
document.documentElement.style.fontSize = document.documentElement.clientWidth/designWidth+"px";
</script>
十一、Flex布局和grid布局的区别
1、Flex布局,W3C在2009年提出的一种布局方案,子元素的float、clear和vertical-align属性失效
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flex 布局</title>
<style>
.flex-container {
display: flex;
/* 1. 以上,定义弹性盒子,取值如下
(1)flex:生成弹性盒子网格容器
(2)inline-flex:生成行内弹性盒子容器 */
flex-direction: row;
/* 2. 以上,主轴方向,取值如下
(1)row(默认值):主轴为水平方向,起点在左端
(2)row-reverse:主轴为水平方向,起点在右端
(3)column:主轴为垂直方向,起点在上沿
(4)column-reverse:主轴为垂直方向,起点在下沿 */
flex-wrap: wrap;
/* 3. 以上,主轴换行,取值如下
(1)nowrap(默认):不换行
(2)wrap:换行,第一行在上方
(3)wrap-reverse:换行,第一行在下方 */
justify-content: space-between;
/* 4. 以上,主轴对齐方式,取值如下
(1)flex-start(默认值):主轴起点对齐
(2)flex-end:主轴终点对齐
(3)center: 主轴居中对齐,之间0间距
(4)space-around:主轴居中对齐,之间小间距,项目与外边框的间隔,是项目之间间隔的一半
(5)space-between:主轴两端对齐,之间大间距,项目与外边框的间隔,是0 */
align-items: center;
/* 5. 以上,交叉轴对齐方式,取值如下
(1)flex-start:交叉轴的起点对齐
(2)flex-end:交叉轴的终点对齐
(3)center:交叉轴的中点对齐
(4)baseline: 项目的第一行文字的基线对齐
(5)stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度 */
gap: 10px;
/* 6. 以上,子项间距,也可分开设置,取值如下
(1)row-gap:行间距
(2)column-gap:列间距 */
height: 200px;
border: 1px solid #ddd;
padding: 10px;
background: #f5f5f5;
}
/* 子项样式 */
.item {
background: #999999;
color: white;
padding: 20px;
text-align: center;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="flex-container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
</body>
</html>
2、grid布局
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Grid 布局</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
h2 {
color: #333;
border-bottom: 2px solid #666;
padding-bottom: 5px;
}
.container {
background-color: #fff;
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.grid-container {
display: grid;
/* 1. 以上,定义网格容器;说明如下 */
/* display: grid; 定义网格容器类型,取值如下
(1)grid:生成块级网格容器
(2)inline-grid:生成行内网格容器 */
grid-template-rows: 80px 1fr 60px; /* 定义行数量和高度 */
grid-template-columns: 400px 1fr; /* 定义列数量和宽度 */
/* 2. 以上,定义行数量和高度、列数量和宽度,取值如下
(1)固定值:100px / 20% / 5em
(2)弹性单位:1fr(剩余空间分配比例)
(3)函数:
- repeat(3, 1fr),重复3列,每列1fr
- repeat(auto-fill, minmax(100px, 1fr));
//auto-fill,自动填充尽可能多的列,即使某些列没有内容
//minmax(100px, auto),列宽最小100px,最大自适应
//minmax(100px, 1fr),列宽最小100px,最大为1fr(等分剩余空间)
(4)auto:由浏览器决定 */
grid-template-areas: /* 在grid容器内,多个header类div只生效第1个div;不管该div是第几个子级,都会渲染到第1行 */
"header header" /* 第一行:header占据两列 */
"sidebar main" /* 第二行:sidebar和main各占一列 */
"footer footer"; /* 第三行:footer 占据两列 */
/* 3. 以上,定义网格区域(可视化布局),通过命名区域定义布局;说明如下
(1)每行用引号定义,空格分隔区域
(2)相同名称区域会被合并 */
gap: 10px;
/* 4. 以上,网格项间距,也可分开设置;说明如下
(1)row-gap:行间距
(2)column-gap:列间距 */
justify-content: center; /* 网格水平对齐方式 */
align-content: center; /* 网格垂直对齐方式 */
/* 5. 以上,网格对齐方式,取值如下
(1)start:左对齐
(2)end:右对齐
(3)center:居中对齐
(4)space-around:居中对齐(两侧有间隙)
(5)space-between:两端对齐(无外侧间隙)
(6)space-evenly:完全均匀分布 */
justify-items: stretch; /* 网格项水平对齐方式 */
align-items: center; /* 网格项垂直对齐方式 */
/* 6. 以上,网格项对齐方式,取值如下
(1)start:左对齐
(2)end:右对齐
(3)center:居中对齐
(4)stretch(默认值):拉伸填满 */
height: 80vh;
background: #999999;
padding: 10px;
}
/* 网格项样式 */
.item {
background-color: #888888;
color: white;
padding: 15px;
text-align: center;
border-radius: 4px;
}
/* 网格项与grid-template-areas绑定 */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer {
grid-area: footer;
/* justify-self: start;单个网格项的水平对齐,覆盖justify-items,取值同justify-items */
/* align-self: end;单个网格项的垂直对齐,覆盖align-items,取值同align-items */
}
</style>
</head>
<body>
<div class="grid-container">
<div class="item header">第一行:header 占据两列</div>
<div class="item sidebar">
<div>第二行:sidebar 占一列</div>
<div>第二行:sidebar 占一列</div>
</div>
<div class="item main">第二行:main占一列</div>
<div class="item footer">第三行:footer 占据两列</div>
</div>
</body>
</html>
十二、多图片延迟加载下载
附、真实案例
const getDetailInfo = () => {
changeRecord({ sid: route.query.sid }).then(res => {
dataInfo.info = JSON.parse(JSON.stringify(res.data));
dataInfo.info.forEach(item => {
item.base64Image = false;
querySaveImage({sid: item.sid}).then(res => {
item.base64Image = AES.decrypt( res.data.base64Image, secretStr )
})
})
})
}
getDetailInfo();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
img {
border: none;
}
div {
margin: 0 auto;
width: 800px;
height: 400px;
background: url("http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518060703_mthumb.jpg") no-repeat center #e1e1e1;
}
div img {
width: 100%;
height: 100%;
}
p {
width: 800px;
height: 600px;
line-height: 60px;
background: lightgrey;
font-size: 30px;
margin: 0 auto;
text-indent: 13px;
}
</style>
</head>
<body>
<p>
<span>多图片延迟加载:</span><br/>
<span>(1)多图片延迟加载;</span><br/>
<span>(2)多图片延迟加载;</span><br/>
<span>(3)多图片延迟加载。</span>
</p>
</body>
<script>
var data = [
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
{
src:
"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1509/06/c5/12227263_12227263_1441518066203_mthumb.jpg",
},
];
var aDiv = document.getElementsByTagName("div");
var aImg = document.getElementsByTagName("img");
function bind() {
var frg = document.createDocumentFragment();
for (var i = 0; i < data.length; i++) {
var div = document.createElement("div");
div.innerhtml = "<img realImg='" + data[i].src + "' alt=''/>";
frg.appendChild(div);
}
document.body.appendChild(frg);
frg = null;
}
bind();
window.onscroll = function () {
var scrollBottom =
document.documentElement.scrollTop + document.documentElement.clientHeight;
for (var i = 0; i < aDiv.length; i++) {
var thisImg = aImg[i];
var thisDiv = aDiv[i];
var imgPosition = thisDiv.offsetTop + thisDiv.offsetHeight;
if (imgPosition - 200 < scrollBottom) {
if (thisImg.isLoad) continue;
thisImg.src = thisImg.getAttribute("realImg");
thisImg.isLoad = true;
}
}
};
/*
当相关服务关闭时,登录页仍然可见,相关图片地址的配置如下
$timeout(function () {
var thisImg = new Image();
thisImg.src = $scope.r_g_company.logoPage.logo.src;
thisImg.onerror= function() {
$scope.r_g_company.logoPage.logo.src = $scope.r_g_company.logoPage.logo.srcCY
}
},1000);
$.get('/app_v3/oem/info?' +new Date().getTime()).then(function (res) {
$scope.r_g_company.logoPage.logo.src = '/audit-html/static/img/cy_oem/logo.png';
}).catch(function(){
$scope.r_g_company.logoPage.logo.src = '/audit-html/static/img/cy_oem/logo.png';
$scope.r_g_company.logoPage.logo.srcCY = '/audit-html/static/img/cy_tech/logo.png';
});
*/
</script>
</html>
十三、canvas绘图
1、五角星和国旗
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>五角星与国旗</title>
<style>
.container {
display: flex;
justify-content: space-around;
align-items: flex-start;
margin: 20px;
}
.canvas-wrapper {
text-align: center;
margin: 0 20px;
}
h1 {
text-align: center;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="canvas-wrapper">
<h1>五角星</h1>
<canvas id="canvas" width="450" height="450"></canvas>
</div>
<!-- canvas标签,默认宽300px; 高150px; 非常重要!!! -->
<div class="canvas-wrapper">
<h1>国旗(半成品)</h1>
<canvas id="flag" width="600" height="400"></canvas>
</div>
</div>
</body>
</html>
<script>
// 绘制单独的五角星
var canvas = document.getElementById("canvas");
var context1 = canvas.getContext("2d");
context1.beginPath();
context1.rotate(18*Math.PI/180);
for (i = 0; i < 5; i++) {
context1.lineTo(
Math.cos((i * 72+36) / 180 * Math.PI) * 200 + 250,
Math.sin((i * 72+36) / 180 * Math.PI) * 200 + 150);
context1.lineTo(
Math.cos((i * 72+72) / 180 * Math.PI) * 75 + 250,
Math.sin((i * 72+72) / 180 * Math.PI) * 75 + 150);
}
context1.fillStyle = "#ff0000";
context1.fill();
context1.closePath();
// 绘制国旗
const flagCanvas = document.getElementById('flag');
const ctx = flagCanvas.getContext('2d');
// 绘制红色背景
ctx.fillStyle = '#de2910';
ctx.fillRect(0, 0, 600, 400);
// 大五角星中心坐标
const bigStarX = 120;
const bigStarY = 120;
// 绘制大五角星
drawStar(ctx, bigStarX, bigStarY, 60, '#ffde00', 0);
// 绘制四个小五角星(修正后的位置和角度)
const smallStars = [
{ x: 180, y: 60, angle: Math.atan2(bigStarY - 60, bigStarX - 180) },
{ x: 210, y: 90, angle: Math.atan2(bigStarY - 90, bigStarX - 210) },
{ x: 210, y: 150, angle: Math.atan2(bigStarY - 150, bigStarX - 210) },
{ x: 180, y: 180, angle: Math.atan2(bigStarY - 180, bigStarX - 180) }
];
smallStars.forEach(star => {
drawStar(ctx, star.x, star.y, 20, '#ffde00', star.angle);
});
// 绘制五角星函数
function drawStar(ctx, cx, cy, radius, color, angle) {
ctx.save();
ctx.fillStyle = color;
ctx.translate(cx, cy);
ctx.rotate(angle);
ctx.beginPath();
for (let i = 0; i < 5; i++) {
const outerAngle = (i * 2 * Math.PI / 5) - Math.PI / 2;
const innerAngle = ((i + 0.5) * 2 * Math.PI / 5) - Math.PI / 2;
ctx.lineTo(
Math.cos(outerAngle) * radius,
Math.sin(outerAngle) * radius
);
ctx.lineTo(
Math.cos(innerAngle) * radius * 0.382,
Math.sin(innerAngle) * radius * 0.382
);
}
ctx.closePath();
ctx.fill();
ctx.restore();
}
</script>
2、党徽与国旗
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>党徽与抗战时期的国旗</title>
<style>
.container {
display: flex;
justify-content: center;
align-items: center;
margin: 20px;
}
.canvas-container {
margin: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="canvas-container">
<canvas id="canvas" width="450" height="450"></canvas>
</div>
<!-- canvas标签,默认宽300px; 高150px; 非常重要!!! -->
<div class="canvas-container">
<canvas id="mainCanvas" width="900" height="600"></canvas>
</div>
</div>
</body>
</html>
<script>
// 以下,党徽绘制代码
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
// 1、绘制深蓝色圆
context.beginPath();
context.arc(215, 215, 200, 0, 2 * Math.PI);
context.fillStyle = "#030d48";
context.strokeStyle = "grey";
context.lineWidth = "10";
context.stroke();
context.fill();
context.closePath();
// 2、绘制12道光芒
context.beginPath();
for (var i = 0; i < 12; i++) {
context.lineTo(
Math.cos((i * 30) / 180 * Math.PI) * 200 + 215,
Math.sin((i * 30) / 180 * Math.PI) * 200 + 215
);
context.lineTo(
Math.cos((i * 30 + 15) / 180 * Math.PI) * 105 + 215,
Math.sin((i * 30 + 15) / 180 * Math.PI) * 105 + 215
);
}
context.fillStyle = "#ffffff";
context.fill();
context.closePath();
// 3、绘制中心圆
context.beginPath();
context.arc(215, 215, 105, 0, 2 * Math.PI);
context.strokeStyle = "#030d48";
context.lineWidth = "10";
context.stroke();
context.closePath();
// 以下,抗战时期国旗绘制代码
const canvas2 = document.getElementById("mainCanvas");
const ctx = canvas2.getContext("2d");
// 1、绘制红色背景
ctx.fillStyle = '#ff0000';
ctx.fillRect(0, 0, canvas2.width, canvas2.height);
// 2、绘制深蓝色背景
ctx.beginPath();
ctx.rect(0, 0, 450, 300);
ctx.fillStyle = "#030d48";
ctx.lineWidth = 5;
ctx.fill();
// 3、绘制12道光芒
ctx.beginPath();
for (let i = 0; i < 12; i++) {
ctx.lineTo(
Math.cos((i * 30) * Math.PI / 180) * 100 + 225,
Math.sin((i * 30) * Math.PI / 180) * 100 + 150
);
ctx.lineTo(
Math.cos((i * 30 + 15) * Math.PI / 180) * 52.5 + 225,
Math.sin((i * 30 + 15) * Math.PI / 180) * 52.5 + 150
);
}
ctx.fillStyle = "#ffffff";
ctx.fill();
// 4、绘制中心圆
ctx.beginPath();
ctx.arc(225, 150, 52.5, 0, Math.PI * 2);
ctx.strokeStyle = "#030d48";
ctx.lineWidth = 5;
ctx.stroke();
</script>
3、时钟
这是用HTML5的canvas制作的一个钟表,包含表盘、时针、分针、秒针及它们的运动;另外还添加了自动读时间的功能
<!doctype html>
<html>
<head>
<style>
body {
background-color: #f0f8ff;
display: flex;
justify-content: center;
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
padding-top: 50px; /* 下移50像素 */
}
#clock-container {
text-align: center;
}
#clock {
display: block;
margin: 0 auto;
}
.time-display {
color: #00796b;
font-size: 20px;
margin-bottom: 15px;
font-family: 'Microsoft YaHei', sans-serif;
}
</style>
</head>
<body>
<div id="clock-container">
<div class="time-display" id="time-display">北京时间: 加载中...</div>
<!-- canvas标签,默认宽300px; 高150px; 非常重要!!! -->
<canvas id="clock" width="500" height="500">
您的浏览器不支持canvas标签,无法看到时钟
</canvas>
</div>
</body>
</html>
<script>
var clock = document.getElementById('clock'); //获取canvas元素
var context = clock.getContext('2d'); //获取2D绘图上下文
var timeDisplay = document.getElementById('time-display'); //获取时间显示元素
function drawClock() { //定义绘制时钟的函数
//以下,更新时钟上面的时间显示
function tow(n) {//定义数字补零函数
return n >= 0 && n < 10 ? '0' + n : '' + n; //小于10的数字补前导零
}
var now = new Date(); //获取当前时间对象
var second = now.getSeconds(); //获取秒数
var minute = now.getMinutes(); //获取分钟数
var hour = now.getHours(); //获取小时数
var date = now.getDate(); //获取日期
var month = now.getMonth() + 1; //获取月份(需+1)
var year = now.getFullYear(); //获取年份
var text = ''; //初始化时间文本
text += "北京时间: " + tow(year) + "年" + tow(month) + "月" + tow(date) + "日 "; //拼接日期
text += tow(now.getHours()) + ":" + tow(minute) + ":" + tow(second); //拼接时分秒
timeDisplay.textContent = text; //更新时间显示内容
//以上,更新时钟上面的时间显示
//以下,清空画布
context.clearRect(0, 0, 500, 500); //清空画布
//以下,绘制时钟背景渐变
var gradient = context.createRadialGradient(250, 270, 0, 250, 270, 220); //创建径向渐变
gradient.addColorStop(0, '#e0f7fa'); //添加渐变起始颜色
gradient.addColorStop(1, '#80deea'); //添加渐变结束颜色
context.fillStyle = gradient; //设置填充样式为渐变
//以下,制作时钟外圈
context.beginPath(); //开始路径绘制
context.arc(250, 270, 220, 0, Math.PI * 2); //绘制背景圆形
context.lineWidth = 15; //设置线条宽度
context.strokeStyle = '#888888'; //设置线条颜色(浅灰)
context.fill(); //填充背景
context.beginPath(); //开始路径绘制
context.arc(250, 270, 200, 0, Math.PI * 2); //绘制外圆
context.stroke(); //绘制外圆边框
context.closePath(); //结束路径
//以下,制作时钟内圈
context.beginPath(); //开始路径绘制
context.lineWidth = 5; //设置线条宽度
context.strokeStyle = '#333333'; //设置线条颜色(深灰)
context.arc(250, 270, 190, 0, Math.PI * 2); //绘制内圆
context.stroke(); //绘制内圆边框
context.closePath(); //结束路径
//以下,小时刻度制作
for (i = 0; i < 12; i++) { //循环12次绘制小时刻度
context.save(); //保存当前绘图状态
context.lineWidth = 8; //设置线条宽度
context.strokeStyle = "#00796b"; //设置线条颜色
context.translate(250, 270); //平移坐标系到圆心
context.rotate(i * 30 * Math.PI / 180); //旋转到对应小时角度
context.beginPath(); //开始路径绘制
context.moveTo(0, -170); //移动到刻度起点
context.lineTo(0, -190); //绘制刻度线
context.stroke(); //绘制刻度
context.closePath(); //结束路径
context.restore(); //恢复绘图状态
};
//以下,分钟刻度制作
for (i = 0; i < 60; i++) { //循环60次绘制分钟刻度
context.save(); //保存当前绘图状态
context.lineWidth = 3; //设置线条宽度
context.strokeStyle = "#00897b"; //设置线条颜色
context.translate(250, 270); //平移坐标系到圆心
context.rotate(i * 6 * Math.PI / 180); //旋转到对应分钟角度
context.beginPath(); //开始路径绘制
context.moveTo(0, -180); //移动到刻度起点
context.lineTo(0, -190); //绘制刻度线
context.stroke(); //绘制刻度
context.closePath(); //结束路径
context.restore(); //恢复绘图状态
};
//以下,钟面上表示小时的数字
for (var i = 1; i < 13; i++) {//循环13次绘制小时数字
context.save(); //保存当前绘图状态
//以下,计算小时数字的位置
var deg = i * Math.PI / 6; //计算对应角度
context.translate(250, 270); //平移坐标系到圆心
var x = Math.sin(deg); //计算x坐标
var y = -Math.cos(deg); //计算y坐标
//以下,绘制小时数字的圆形背景
context.beginPath(); //开始路径绘制
context.arc(x * 155, y * 155, 20, 0, Math.PI * 2); //绘制数字背景圆
context.fillStyle = '#00796b'; //设置填充颜色
context.fill(); //填充背景圆
context.strokeStyle = '#004d40'; //设置边框颜色
context.lineWidth = 2; //设置边框宽度
context.stroke(); //绘制边框
//以下,绘制小时数字
context.fillStyle = "white"; //设置文本颜色
context.font = "bold 20px Arial"; //设置字体样式
context.textAlign = "center"; //设置文本居中
context.textBaseline = "middle"; //设置文本垂直居中
context.fillText(i, x * 155, y * 155); //绘制数字文本
context.restore(); //恢复绘图状态
};
//以下,中心装饰点
context.beginPath(); //开始路径绘制
context.arc(250, 270, 10, 0, Math.PI * 2); //绘制中心圆
context.fillStyle = 'green'; //设置填充颜色
context.fill(); //填充中心圆
context.strokeStyle = 'yellow'; //设置边框颜色
context.lineWidth = 3; //设置边框宽度
context.stroke(); //绘制边框
//以下,时针制作
context.save(); //保存当前绘图状态
context.lineWidth = 8; //设置线条宽度
context.strokeStyle = "#333"; //设置线条颜色
context.lineCap = "round"; //设置线条端点样式
context.translate(250, 270); //平移坐标系到圆心
context.rotate(hour * 30 * Math.PI / 180); //旋转到对应小时角度
context.beginPath(); //开始路径绘制
context.moveTo(0, 15); //移动到时针起点
context.lineTo(0, -90); //绘制时针
context.stroke(); //绘制时针
context.closePath(); //结束路径
context.restore(); //恢复绘图状态
//以下,分针制作
context.save(); //保存当前绘图状态
context.lineWidth = 5; //设置线条宽度
context.strokeStyle = "#555"; //设置线条颜色
context.lineCap = "round"; //设置线条端点样式
context.translate(250, 270); //平移坐标系到圆心
context.rotate(minute * 6 * Math.PI / 180); //旋转到对应分钟角度
context.beginPath(); //开始路径绘制
context.moveTo(0, 15); //移动到分针起点
context.lineTo(0, -130); //绘制分针
context.stroke(); //绘制分针
context.closePath(); //结束路径
context.restore(); //恢复绘图状态
//以下,秒针制作
context.save(); //保存当前绘图状态
context.strokeStyle = "#e53935"; //设置线条颜色
context.fillStyle = "#e53935"; //设置填充颜色
context.lineWidth = 2; //设置线条宽度
context.lineCap = "round"; //设置线条端点样式
context.translate(250, 270); //平移坐标系到圆心
context.rotate(second * 6 * Math.PI / 180); //旋转到对应秒数角度
context.beginPath(); //开始路径绘制
context.moveTo(0, 20); //移动到秒针起点
context.lineTo(0, -160); //绘制秒针
context.stroke(); //绘制秒针
context.closePath(); //结束路径
//以下,秒针尾部装饰
context.beginPath(); //开始路径绘制
context.arc(0, 0, 5, 0, Math.PI * 2); //绘制尾部装饰圆
context.fill(); //填充装饰圆
context.stroke(); //绘制装饰圆边框
//以下,秒针头部装饰
context.beginPath(); //开始路径绘制
context.arc(0, -150, 8, 0, Math.PI * 2); //绘制头部装饰圆
context.fill(); //填充装饰圆
context.stroke(); //绘制装饰圆边框
context.restore(); //恢复绘图状态
}
drawClock(); //首次绘制时钟
setInterval(drawClock, 1000); //每秒更新一次时钟
</script>
十四、弹窗
1、弹窗-系统内置
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body style="font-size: 30px;">
<pre>
alert:
1、弹-窗有确定按钮,阻塞线程,
2、alert后面的代码,点击确认后才执行
confirm:
1、弹-窗有两个按钮(确定和取消),阻塞线程,
2、confirm后面的代码,点击按钮后才执行,
3、点击确定返回true,点击取消返回false
prompt:
1、弹-窗有一个输入框、两个按钮(确定和取消),阻塞线程
2、prompt后面的代码,点击按钮后才执行,
3、点击确定返回输入内容,为空返回空字符串,点击取消返回null
</pre>
<input type="button" onclick="fnAlert()" value="显示alert框" />
<input type="button" onclick="fnConfirm()" value="显示confirm框" />
<input type="button" onclick="fnPrompt()" value="显示prompt框" />
</body>
</html>
<script>
function fnAlert(){
var text = alert("你好,我是一个alert框!");
console.log( text );
}
function fnConfirm(){
var text = confirm("你好,我是一个confirm框!");
console.log( text );
}
function fnPrompt(){
var text = prompt("你好,我是一个prompt框!","这是默认输入!");
console.log( text );
}
</script>
2、弹窗-手写(可拖拽和缩放)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>弹窗-可拖拽和缩放</title>
<style>
* {
padding: 0;
margin: 0;
}
html,body {
height: 100%;
}
.mask {
position: fixed;
width: 100%;
height: 100%;
background: #bbb;
}
#alert {
position: absolute;
background: #ddd;
margin: auto;
width: 600px;
height: 800px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
user-select: none;
resize: both;
overflow: auto;
}
.innerBox {
padding: 0 30px;
}
p {
line-height: 40px;
}
.title {
height: 50px;
line-height: 50px;
background: gray;
padding-left: 30px;
cursor: pointer;
}
.submit{
text-align: center;
background: gray;
display: block;
margin: 0 auto;
width:100px;
height:30px;
line-height: 30px;
}
</style>
</head>
<body>
<div class="mask">
<div id="alert">
<p id="alert-title-id" class="title"> 本弹窗特征(鼠标置于此处,方可拖动): </p>
<div class="innerBox">
<p> 1、标题区可拖拽 </p>
<p> 2、内容区可以是任意高度、宽度 </p>
<p> 3、初始位置居中,由下面css决定 </p>
<div style="padding-left:30px;">
<p> left: 50%; </p>
<p> top: 50%;</p>
<p> transform: translate(-50%, -50%);</p>
</div>
<p> 4、弹-窗可缩放,由下面css决定 </p>
<div style="padding-left:30px;">
<p> resize: both; </p>
<p> overflow: auto;</p>
</div>
<p> 5、提交按钮和文字居中,由下面css决定 </p>
<div style="padding-left:30px;">
<p> text-align:center; width:100px; background:gray;</p>
<p> display:block; height:30px; line-height:30px; margin:0 auto;</p>
</div>
<p> 6、你使用时,在关闭弹-窗之前,用上面3处css代码重置弹-窗的位置,否则,下次使用弹-窗时,弹-窗将出现在上次关闭时的地方。 </p>
<p> 7、弹-窗向任何方向(上下左右)拖拽,当消失3/4时,停止移动。 </p>
<p> 8、拖拽弹-窗的右下方,可以实现缩放。 </p>
</div>
<div style="padding-top:30px;">
<span class="submit">提交</span>
</div>
</div>
</div>
</body>
</html>
<script>
var oDiv = document.getElementById("alert");
oDiv.onmousedown = down;
function processThis(fn, currentThis) {
return function (event) {
fn.call(currentThis, event); //”先触发,后执行“与”先执行,后触发“
};
}
function down(event) {
event = event || window.event;
if (event.target.id != "alert-title-id") return;
this.initOffsetLeft = this.offsetLeft;
this.initOffsetTop = this.offsetTop;
this.initClientX = event.clientX;
this.initClientY = event.clientY;
this.maxOffsetWidth =
(document.documentElement.clientWidth || document.body.clientWidth) -
this.offsetWidth;
this.maxOffsetHeight =
(document.documentElement.clientHeight || document.body.clientHeight) -
this.offsetHeight;
if (this.setCapture) {
this.setCapture();
this.onmousemove = processThis(move, this);
this.onmouseup = processThis(up, this);
} else {
document.onmousemove = processThis(move, this);
document.onmouseup = processThis(up, this);
}
}
function move(event) {
var currentLeft = this.initOffsetLeft + (event.clientX - this.initClientX);
var currentTop = this.initOffsetTop + (event.clientY - this.initClientY);
//以下都是边界值的判断;弹窗向任何方向(上下左右)拖拽,当消失3/4时,停止移动。
if (currentLeft > this.maxOffsetWidth + this.clientWidth / 0.8) {
currentLeft = this.maxOffsetWidth + this.clientWidth / 0.8;
} else if (currentLeft < -this.clientWidth / 4) {
currentLeft = -this.clientWidth / 4;
}
if (currentTop > this.maxOffsetHeight + this.clientHeight / 0.8) {
currentTop = this.maxOffsetHeight + this.clientHeight / 0.8;
} else if (currentTop < 300) {
//-this.clientHeight / 4
currentTop = 300; //-this.clientHeight / 4
}
//以上都是边界值的判断;弹-窗向任何方向(上下左右)拖-拽,当消失3/4时,停止移动。
//以下都是边界值的判断;弹-窗向任何方向(上下左右)拖-拽,当消失1/2时,停止移动。
/* if (currentLeft > this.maxOffsetWidth + this.clientWidth) {
currentLeft = this.maxOffsetWidth + this.clientWidth;
} else if (currentLeft < -this.clientWidth / 64) {
currentLeft = -this.clientWidth / 64;
}
if (currentTop > this.maxOffsetHeight + this.clientHeight) {
currentTop = this.maxOffsetHeight + this.clientHeight;
} else if (currentTop < -this.clientHeight / 64) {
currentTop = -this.clientHeight / 64;
} */
//以上都是边界值的判断;弹-窗向任何方向(上下左右)拖-拽,当消失1/2时,停止移动。
//以下都是边界值的判断;弹-窗向任何方向(上下左右)拖-拽,触边时,停止移动。
/* if (currentLeft > this.maxOffsetWidth + this.clientWidth / 2) {
currentLeft = this.maxOffsetWidth + this.clientWidth / 2;
} else if (currentLeft < this.clientWidth / 2) {
currentLeft = this.clientWidth / 2;
}
if (currentTop > this.maxOffsetHeight + this.clientHeight / 2) {
currentTop = this.maxOffsetHeight + this.clientHeight / 2;
} else if (currentTop < this.clientHeight / 2) {
currentTop = this.clientHeight / 2;
} */
//以上都是边界值的判断;弹-窗向任何方向(上下左右)拖-拽,触边时,停止移动。
this.style.left = currentLeft + "px";
this.style.top = currentTop + "px";
console.log(this.style.left);
console.log(this.style.top);
}
function up() {
if (this.releaseCapture) {
this.releaseCapture();
this.onmousemove = null;
this.onmouseup = null;
} else {
document.onmousemove = null;
document.onmouseup = null;
}
}
</script>
十五、表格排序
说明,这里的表格排序,包含按姓名、年龄、分数、性别等汉字和数字的排序。用纯原生JavaScript代码实现,同时还实现了隔行变色。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
#table {
width: 600px;
border: 3px solid darkgreen;
margin: 20px auto;
text-align: center;
}
#table tr {
height: 40px;
line-height: 40px;
}
.bg0 {
background: mediumvioletred;
}
.bg1 {
background: greenyellow;
}
.bg2 {
background: yellow;
}
.cursor {
cursor: pointer
}
</style>
</head>
<body>
<table id="table" class="table">
<thead>
<tr class="bg2">
<th class="cursor">姓名</th>
<th class="cursor">年龄</th>
<th class="cursor">分数</th>
<th class="cursor">性别</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>
</html>
<script>
var table = document.getElementById("table");
var th = table.tHead.rows[0].cells;
var body = table.tBodies[0];
var row = body.rows;
console.log(row);
console.log('上面,展开前是空数组,这是代码执行到此的结果');
console.log('上面,展开后有6项数据,这是页面渲染完毕后的结果');
var data = [
{ name: "赵老大", age: 45, score: 60, sex: 0 },
{ name: "钱老二", age: 24, score: 67, sex: 1 },
{ name: "孙老三", age: 38, score: 79, sex: 1 },
{ name: "李老四", age: 30, score: 80, sex: 0 },
{ name: "周老五", age: 65, score: 56, sex: 1 },
{ name: "吴老六", age: 26, score: 26, sex: 0 },
];
//绑定原始数据
bind();
function bind() {
var frg = document.createDocumentFragment();
for (var i = 0; i < data.length; i++) {
var cur = data[i];
var tr = document.createElement("tr");
for (var attr in cur) {
if (attr === "sex") {
cur[attr] = cur[attr] === 0 ? "男" : "女";
}
var td = document.createElement("td");
td.innerHTML = cur[attr];
tr.appendChild(td);
}
frg.appendChild(tr);
}
body.appendChild(frg); //2、
frg = null;
}
//实现隔行变色
changeColor();
function changeColor() {
for (var i = 0; i < row.length; i++) {
row[i].className = "bg" + (i % 2);
}
}
//绑定点击事件
for (var i = 0; i < th.length; i++) {
if (th[i].className === "cursor") {
th[i].flag = -1;
th[i].index = i;
th[i].onclick = function () {
sortArray.call(this, this.index);
};
}
}
//类数组转化为数组
function makeArray(arg) {
var ary = [];
try {
ary = Array.prototype.slice.call(arg);
} catch (e) {
for (var i = 0; i < arg.length; i++) {
ary.push(arg[i]);
}
}
return ary;
}
//点击事件中的排序
function sortArray(n) {
var that = this;
for (var i = 0; i < th.length; i++) {
th[i].flag = i === n ? (that.flag *= -1) : -1;
}
var ary = makeArray(row);
ary.sort(function (rowBefore, rowBehind) {
var rowInnerBefore = rowBefore.cells[n].innerHTML;
var rowInnerBehind = rowBehind.cells[n].innerHTML;
return rowInnerBefore.localeCompare(rowInnerBehind);
});
var frg = null;
for (i = 0; i < ary.length; i++) {
frg = ary[i];
body.appendChild(frg);
}
changeColor();
}
</script>
十六、拖拽
1、拖拽-普通
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>拖拽-普通</title>
<style>
*{
margin:0;
padding:0;
}
div{
position: absolute;
left:0;
top:0;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="div"></div>
</body>
</html>
<script>
var oDiv = document.getElementById("div");
oDiv.onmousedown = down;
function processThis(fn, obj) {
return function (e) {
fn.call(obj, e);
};
}
function down(event) {
event = event || window.event;
this.offsetLeftPass = this.offsetLeft;
this.offsetTopPass = this.offsetTop;
this.eventClientX = event.clientX;
this.eventClientY = event.clientY;
if (this.setCapture) {
this.setCapture();
this.onmousemove = processThis(move, this);
this.onmouseup = processThis(up, this);
} else {
document.onmousemove = processThis(move, this);
document.onmouseup = processThis(up, this);
}
}
function move(event) {
event = event || window.event;
this.style.left =
this.offsetLeftPass + (event.clientX - this.eventClientX) + "px";
//this.offsetLeftPass:移动前offsetLeft值;(event.clientX-this.eventClientX):鼠标横向移动的距离,即盒子横向移动的距离
this.style.top =
this.offsetTopPass + (event.clientY - this.eventClientY) + "px";
//this.offsetTopPass:移动前offsetTop值;(event.clientX-this.eventClientX):鼠标纵向移动的距离,即盒子纵向移动的距离
}
function up() {
if (this.releaseCapture) {
this.releaseCapture();
this.onmousemove = null;
this.onmouseup = null;
} else {
document.onmousemove = null;
document.onmouseup = null;
}
}
</script>
2、拖拽-zTree
<!DOCTYPE html>
<html>
<head>
<title>拖拽-zTree</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="https://cdn.bootcss.com/zTree.v3/3.5.33/css/zTreeStyle/zTreeStyle.min.css">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/zTree.v3/3.5.33/js/jquery.ztree.core.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/zTree.v3/3.5.29/js/jquery.ztree.excheck.js"></script>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/zTree.v3/3.5.29/js/jquery.ztree.exedit.js"></script>
<script type="text/javascript">
var setting = {
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false
},
data: {
simpleData: {
enable: true
}
},
callback: {
beforeDrag: beforeDrag,
beforeDrop: beforeDrop
}
};
var zNodes =[
{ id:1, pId:0, name:"随意拖-拽 1", open:true},
{ id:11, pId:1, name:"随意拖-拽 1-1"},
{ id:12, pId:1, name:"随意拖-拽 1-2", open:true},
{ id:121, pId:12, name:"随意拖-拽 1-2-1"},
{ id:122, pId:12, name:"随意拖-拽 1-2-2"},
{ id:123, pId:12, name:"随意拖-拽 1-2-3"},
{ id:13, pId:1, name:"禁止拖-拽 1-3", open:true, drag:false},
{ id:131, pId:13, name:"禁止拖-拽 1-3-1", drag:false},
{ id:132, pId:13, name:"禁止拖-拽 1-3-2", drag:false},
{ id:133, pId:13, name:"随意拖-拽 1-3-3"},
{ id:2, pId:0, name:"随意拖-拽 2", open:true},
{ id:21, pId:2, name:"随意拖-拽 2-1"},
{ id:22, pId:2, name:"禁止拖-拽到我身上 2-2", open:true, drop:false},
{ id:221, pId:22, name:"随意拖-拽 2-2-1"},
{ id:222, pId:22, name:"随意拖-拽 2-2-2"},
{ id:223, pId:22, name:"随意拖-拽 2-2-3"},
{ id:23, pId:2, name:"随意拖-拽 2-3"}
];
function beforeDrag(treeId, treeNodes) {
for (var i=0,l=treeNodes.length; i<l; i++) {
if (treeNodes[i].drag === false) {
return false;
}
}
return true;
}
function beforeDrop(treeId, treeNodes, targetNode, moveType) {
return targetNode ? targetNode.drop !== false : true;
}
function setCheck() {
var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
isCopy = $("#copy").attr("checked"),
isMove = $("#move").attr("checked"),
prev = $("#prev").attr("checked"),
inner = $("#inner").attr("checked"),
next = $("#next").attr("checked");
zTree.setting.edit.drag.isCopy = isCopy;
zTree.setting.edit.drag.isMove = isMove;
showCode(1, ['setting.edit.drag.isCopy = ' + isCopy, 'setting.edit.drag.isMove = ' + isMove]);
zTree.setting.edit.drag.prev = prev;
zTree.setting.edit.drag.inner = inner;
zTree.setting.edit.drag.next = next;
showCode(2, ['setting.edit.drag.prev = ' + prev, 'setting.edit.drag.inner = ' + inner, 'setting.edit.drag.next = ' + next]);
}
function showCode(id, str) {
var code = $("#code" + id);
code.empty();
for (var i=0, l=str.length; i<l; i++) {
code.append("<li>"+str[i]+"</li>");
}
}
$(document).ready(function(){
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
setCheck();
$("#copy").bind("change", setCheck);
$("#move").bind("change", setCheck);
$("#prev").bind("change", setCheck);
$("#inner").bind("change", setCheck);
$("#next").bind("change", setCheck);
});
</script>
</head>
<body>
<p>参考文档1,https://treejs.cn/v3/main.php#_zTreeInfo</p>
<p>参考文档2,https://www.bootcdn.cn/zTree.v3/3.5.29</p>
<div class="content_wrap">
<div class="zTreeDemoBackground left">
<ul id="treeDemo" class="ztree"></ul>
</div>
<div class="right">
<ul class="info">
<li class="title"><h2>1、setting 配置信息说明</h2>
<ul class="list">
<li>此 Demo 仅从功能上演示实现拖拽的基本方法和配置参数</li>
<li class="highlight_red">1)、使用拖-拽功能,必须设置 setting.edit 中的各个属性,详细请参见 API 文档中的相关内容</li>
<li class="highlight_red">2)、使用拖-拽功能的事件回调函数,必须设置 setting.callback.beforeDrag / onDrag / beforeDrop / onDrop 等属性,详细请参见 API 文档中的相关内容</li>
<li><p>基本拖-拽设置:<br/>
<input type="checkbox" id="copy" class="checkbox first" checked /><span>允许复制</span>
<input type="checkbox" id="move" class="checkbox " checked /><span>允许移动</span><br/>
<ul id="code1" class="log" style="height:42px;"></ul></p>
</li>
<li><p>拖-拽相对位置设置:<br/>
<input type="checkbox" id="prev" class="checkbox first" checked /><span>prev</span>
<input type="checkbox" id="inner" class="checkbox " checked /><span>inner</span>
<input type="checkbox" id="next" class="checkbox " checked /><span>next</span><br/>
<ul id="code2" class="log" style="height:65px;"></ul></p>
</li>
</ul>
</li>
<li class="title"><h2>2、treeNode节点数据说明</h2>
<ul class="list">
<li>对节点数据没有特殊要求,用户可以根据自己的需求添加自定义属性</li>
</ul>
</li>
</ul>
</div>
</div>
</body>
</html>