JS笔记
JSON
import json
# 对象转字符串
str = json.dumps(dict,ensure_ascii=False)
# ensure_ascii=True或不设置
str = json.dumps(dict) # 这时前端拿到的是未解码的数据:{"key1":"\u7528\u6237\u8f93...", ...}
obj = json.loads(str) # 字符串转对象
js
JSON.parse(str) # 字符串转字典
JSON.stringify(dict) # 字典转字符串
js中:日期格式化
var ss = Date.parse(ar.create_time);
var date = new Date(ss);
p.innerText = ar.user + " " + date.toDateString();
js中变量加 var 是局部变量不加var 是全局变量
jQuery
$(..).prop(属性名)
$(..).prop(属性名, 属性值)
页面错误提示
<span id="errormsg" style="color:red;"></span>
...
#JS
$('#errormsg').text("错误信息") # 在span元素中显示错误信息
数组遍历
for
var name = ['Peter','Stark','Jack'];
// for 循环
for(var i = 0; i < name.length; i++) {
console.log(name[i]);
}
var name = ['Peter','Stark','Jack'];
// 先缓存 name.length
for(var i = 0, len = name.length; i < len; i++) {
console.log(name[i]);
}
while
// while 循环
var i = 0;
while (i < name.length) {
console.log(name[i]);
i++;
}
//while 逆向遍历
var i = name.length;
while (i--) {
console.log(name[i]);
}
for in
数组既可遍历对象,也可遍历数组。遍历数组时也会遍历非数字键名,所以不推荐 for..in 遍历数组
var a = [1, 2, 3];
for (var key in a) {
console.log(a[key]);
}
const object = {
name: 'Peter',
age: 12,
isHuman: true
};
for (let key in object) {
console.log(key + '---' + object[key]);
}
for of (ES6)
var arr = ['a','b','c'];
for(let item of arr) {
console.log(item);
}
forEach()
用来遍历数组中的每一项,不影响原数组,性能差
缺陷 你不能使用break语句中断循环,也不能使用return语句返回到外层函数
var arr = [1,2,3,4];
arr.forEach = (function(item) {
console.log(item);
})
const info = [
{id: 1000, name: 'zhangsan'},
{id: 1001, name: 'lisi'},
{id: 1002, name: 'wangwu'}
]
arr.forEach( function(item) {
console.log(item.id + '---' + item.name);
})
map()
支持return,相当与原数组克隆了一份,把克隆的每项改变了,不影响原数组
var arr = [1,2,3,4];
arr.map( function(item) {
return item;
})
var arr = ['a','b','c'];
var newArray = arr.map(x => x);
alert(newArray); // ['a','b''c']
var newArray = arr.map(function (item) {
return [expression];
})
JS使用make safe字符串
nav.innerHTML = arg.data.pagination_str;
a标签不跳转的三种方法
# 1:onclick时间返回false:
<a href="https://www.baidu.com" onclick="return false">a标签不跳转</a>
# 2:用href伪协议;
写法一:最常用的方法,也是最周全的方法,void是一个操作符,void(0)返回undefined,地址不发生跳转。
<a href="javaScript:void(0);">a标签不跳转</a>
写法二:这种写法跟写法一类似,区别只是执行了一条空的js代码。
<a href="javaScript:;">a标签不跳转</a>
# 3、使用(#)
跳转到当前页面顶部,当页面内容较多时,还是会有跳转的感觉。不推荐使用
<a href="#">a标签不跳转</a>
JS代码操作表格行的添加和删除
...
<tbody id='tb'>
...
#JS
<script>
function createRow(data, nid) {
var tr = document.createElement('tr'); # 创建表格行
var tdId = document.createElement('td'); # 创建id单元格
tdId.innerHTML = nid;
$(tr).append(tdId)
var tdUser = document.createElement('td'); # 创建User单元格
tdUser.innerHTML = data.username;
$(tr).append(tdUser)
var tdAge = document.createElement('td'); # 创建年龄单元格
tdAge.innerHTML = data.age;
$(tr).append(tdAge)
var tdClass = document.createElement('td'); # 创建班级单元格
# 找到页面中name=cls_id的select,并从select中找到value=data.cls_id的option,取出这个option的text
var text = $('select[name="cls_id"]).find('option[value="'+data.cls_id+"']).text()
tdClass.innerHTML = text;
$(tr).append(tdClass)
...
# 添加行的删除和编辑按钮
var tdEdit = '<td style="font-size: 20px;"><a class="glyphicon glyphicon-remove icon"></a><a class="fa fa-pencil-square-o icon"></a></td>';
$(tr).append(tdEdit)
$('#tb').append(tr) # 将新行添加到表格中
}
</script>
删除行
# 给所有表格行的删除按钮添加 class:del—row
<td style="font-size: 20px;">
<a class="glyphicon glyphicon-remove icon del-row"></a>
<a class="fa fa-pencil-square-o icon"></a>
</td>
# 绑定删除按钮事件
<script>
$(function(){
...
bindDel();
...
}
function bindDel(){
$('.del-row').click(function(){
$('#delModal').modal('show');
// 获得当前行id
var rowID = $(this).parent().parent().attr('nid');
// 在模态框里添加了一个id=delNid的input隐藏标签,方便记录和给后台提交删除记录的id
$('#delNid').val(rowID);
})
}
</script>
事件委托
$(‘要绑定标签的上级标签’).on(‘click’, ‘要绑定的标签’, function() {})
# 旧版本
$(‘要绑定标签的上级标签’).delegate(‘要绑定的标签’, ‘click’, function() {})
target定义(英译:目标,目的):
target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。
语法:
event.target
event.target.nodeName //获取事件触发元素标签name(li,p...)
event.target.id //获取事件触发元素id
event.target.className //获取事件触发元素classname
event.target.innerHTML //获取事件触发元素的内容(li)
等。。。
jquery:this 与 e.target区别
this会冒泡。e.target不冒泡就是指向事件触发的dom。
(这里说的this会冒泡,就是指的是会将目标函数点击的事件不自身处理,将事件委托到他的父元素节点上
。例如下面的例子,e.target指的是目标函数)
HTML部分
<ul>
<li><b>Click me!</b></li>
<li class="li">You can also <b>Click me!</b></li>
</ul>
#JS部分
<stript>
$('li').click(function(e){ //点击的是<b>标签的时候
console.log($(e.target)); // 返回值指的是<b>
console.log($(this)); //返回值值的是<li>
})
</stript>
#正确的事件委托使用方法
<stript>
$('ul').click(function(e){
if(e.target.className==='li'){//点击元素下面的class为li的元素
console.log($(e.target))
}
});
或者
$('ul').on('click',function(e){
if(e.target.nodeName.toLowerCase() === 'li'){//点击li标签的时候出发。注意:点击li里面的元素也是不行的,必须点击li标签
console.log('123')
}
});
</stript>
原理
三种写法
# 1、用on方法
$(function(){
$("#lists").on("click","li",function(event){
var target = $(event.target);
target.css("background-color","red");
})
})
# 2.用delegate()方法
$(function(){
$("#lists").delegate("li","click",function(event){
var target = $(event.target);
target.css("background-color","red");
})
})
#on()方法和delegate()方法对于事件委托的写法很像。
#并且执行事件委托的时候只有子元素(本文中的li)会触发事件,
#而代为执行的父元素(本文中为ul)不会触发事件,所以我们不需要盘判断触发事件的元素节点名,这一点明显优于原生的JavaScript。
# 3.用bind()方法
$(function(){
$("#lists").bind("click","li",function(event){
var target = $(event.target);
if(target.prop("nodeName")=="LI"){
target.css("background-color","red");}
})
})
#bind()方法同原生的JavaScript实现方法一样,当父元素代子元素执行事件时,父元素也会触发事件,
#所以我们需要判断一下触发事件的元素名。此外,用bind()方法给元素绑定事件的时候要注意,
#它只能给已经存在DOM元素添加事件,不能给未来存在DOM
JS添加行的完善
// 由于事件绑定只在网页加载完成的时候进行,
// 因此即使JS添加行时,给按钮添加了class:del-row,
// 该按钮的点击依然不会触发点击函数
// 完善:在事件绑定时,不会行的删除按钮进行点击绑定,改为给table添加事件委托
<script>
...
function bindDel(){
$('#tb').on('click', '.del-row', function(){
$('#delModal').modal('show');
// 获得当前行id
var rowID = $(this).parent().parent().attr('nid');
// 在模态框里添加了一个id=delNid的input隐藏标签,方便记录和给后台提交删除记录的id
$('#delNid').val(rowID);
})
}
</script>
模态框编辑数据相关
<body>
...
{% for row in stu_list %}
<tr nid="{{ row.id }}">
<td na="nid">{{ row.id }}</td>
<td na="user">{{ row.username }}</td>
<td na="age">{{ row.age }}</td>
<td na="gender">{{ row.gender }}</td>
<td na="cls_id" cid="{{ row.cls.id }}">{{ row.cls.title }}</td>
<td style="font-size: 20px;">
<a class="glyphicon glyphicon-remove icon del-row"></a>
<a class="fa fa-pencil-square-o icon edit-row"></a>
</td>
</tr>
{% endfor %}
...
<script>
function bindEdit(){
$('#tb').on('click','.edit-row',function () {
$('#editModal').modal('show');
// 获取当前行的所有数据
// 将数据赋值到对应对话框的指定位置
$(this).parent().prevAll().each(function () {
var v = $(this).text();
var n = $(this).attr('na');
if(n=='cls_id'){
var cid = $(this).attr('cid');
$('#editModal select[name="cls_id"]').val(cid);
}else if(n=='gender'){
if(v=='True'){
$('#editModal :radio[value="1"]').prop('checked',true);
}else{
$('#editModal :radio[value="0"]').prop('checked',true);
}
}else{
$("#editModal input[name='"+ n + "']").val(v)
}
});
})
}
</script>
</body>
其它
var list = [];
list.push("123") # 将python中append
# form
$('#form_id').serialize() // 将form中的数据存为字典,即get/post时发送请求的数据
window.location.href='http://www.*****.com'; // JS跳转
js的空值
JavaScript本身没有判断一个变量是不是空值的函数,因为变量有可能是string,object,number,boolean等类型,类型不同,判断方法也不同。
https://zhuanlan.zhihu.com/p/325874564
function isEmpty(v) {
switch (typeof v) {
case 'undefined':
return true;
case 'string':
if (v.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
break;
case 'boolean':
if (!v) return true;
break;
case 'number':
if (0 === v || isNaN(v)) return true;
break;
case 'object':
if (null === v || v.length === 0) return true;
for (var i in v) {
return false;
}
return true;
}
return false;
}
一些实践记录
ajax、事件委托、dom操作:
<script>
$(function () {
bindPagination(); # 添加事件委托给分页控件的ul
loadArticles(); # 加载文章数据
});
function bindPagination() {
$('#ulpagination').on('click', "li", function(event){
var p = event.target.getAttribute('p'); #event.target就是点击的a标签,a标签有页码属性“p”
if (p==null){ return false;} # 如果页码属性”p“没有定义,说明没有对应的页,则返回。
$.get({ #ajax
url:event.target.getAttribute('base_url'), # a标签中还有base_url属性,指定往哪里发送请求
dataType:'JSON',
data:{'p':p},
success:function (arg) {
list = JSON.parse(arg.data.articles); #data的articles是对象序列化得到的字典字符串,需要再次json解析
createArticleElements(list); # 创建和添加文章元素
ul = document.getElementById('ulpagination');
ul.innerHTML = arg.data.pagination_str; # 添加分页控件。注意innerHTML与innerText有区别
}
})
})
}
function loadArticlesBy(ths,filter,param) { # 根据标签/分类/日期请求文章数据
console.log(filter,param);
myClass = 'my_active'; # a标签的className
if (ths.className.split(" ").indexOf(myClass) >= 0){ #点击的a标签是否已经有这个className
return false; # 如果有了,说明已经按这个条件筛选了。不需要重新请求文章数据了
}
var url = "/{{ blog.site }}/" + filter + "/" + param + "/";
console.log(url);
$.get({
url:url,
dataType:'JSON',
success:function (arg) {
if (arg.status){
list = JSON.parse(arg.data.articles);
createArticleElements(list);
ul = document.getElementById('ulpagination');
ul.innerHTML = arg.data.pagination_str;
{# a = document.getElementsByTagName('a');#}
al = $("a[mya]"); #拿到设置了mya属性的a标签,是一个数组
for (var i=0,len = al.length;i<len;i++){
$(al[i]).removeClass(myClass); # 清除所有a标签class的myClass类
}
$(ths).addClass(myClass); # 将被点击的a标签的class添加myClass
}
}
});
}
function loadArticles(){
var url = "/{{ blog.site }}/articles/";
$.get({
url:url,
dataType:'JSON',
success:function (arg) {
if (arg.status){
list = JSON.parse(arg.data.articles);
createArticleElements(list);
ul = document.getElementById('ulpagination');
ul.innerHTML = arg.data.pagination_str;
}
}
});
}
function createArticleElements(articles) {
ul = document.getElementById('ulArticles');
while (ul.children.length>0) # 清除ul中的子元素,即文章li
ul.removeChild(ul.lastElementChild);
for (var i=0,len=articles.length; i<len; i++) {
ar = articles[i].fields; #用django serialeriz序列化的对象的属性在fields里面
arID = articles[i].pk; #用django serialeriz序列化的对象id变成pk
li = document.createElement('li');
h = document.createElement('h3');
h.innerText = ar.title; # 设置文本的方法
li.appendChild(h);
ul.appendChild(li);
sum = document.createElement('div');
sum.setAttribute('class', 'article-summary'); #设置属性的方法
sum.innerText = ar.summary;
li.appendChild(sum);
p = document.createElement('p');
p.innerText = ar.create_time;
li.appendChild(p);
s1 = document.createElement('span');
s1.innerText = ' 评论数:' + ar.comment_count;
p.appendChild(s1);
s2 = document.createElement('span');
s2.innerText = '点赞数:' + ar.up_count;
p.appendChild(s2);
a = document.createElement('a');
a.innerText = ' 编辑';
a.setAttribute('href', '/articles/' + arID + "/edit/");
p.appendChild(a);
}
}
</script>
for循环删除子标签的问题
报错:Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.
目的:JS 动态表格,读取数据创建表格,点击删除单元格删除该行。
问题:删除时,删除第一行后,再删除第二行会造成第三行删除,并且最终剩下的一行无法删除。
原因:tbody.removeChild(tbody.children[i])
中每次删除后,
tbody.children[i] 的值就变成了删除前的tbody.children[i+1]。
解决方案:改为 tbody.removeChild(this.parentNode);
正确方法:
while (ul.children.length>0):
ul.removeChild(ul.lastElementChild);
document DOM节点的attributes
NamedNodeMap 对象
在 HTML DOM 中, the NamedNodeMap 对象 表示一个无顺序的节点列表。
我们可通过节点名称来访问 NamedNodeMap 中的节点。
获取class属性值:
console.log(ths.className); 如果没有定义,返回空字符串
console.log(ths.attributes.getNamedItem('class')); 如果没有定义,返回undefined
都可以获取class 如:class="a b c" 就返回 字符串“a b c”
jQuery对象与DOM对象之间的转换方法
jQuery对象是包装DOM对象后产生的,但是两者却不能混用,DOM对象才能使用DOM方法,jQuery对象才能使用jQuery方法,以下介绍两者转换的方法:
#jQuery对象转成DOM对象:
(1)jQuery对象实际上是一个数据对象,可以通过[index]方法获得相应的DOM对象。
如:var $v=$("#v"); //得到jQuery对象
var v=$("v")[0];//转换成DOM对象
(2)jQuery本身可以通过.get(index)方法得到相应的DOM对象
如:var $v=$("#v"); //得到jQuery对象
var v=$v.get(0);
#DOM对象转成jQuery对象:
对于已经是一个DOM对象,只需要用$()将DOM对象包装起来,就能获得jQuery对象了
如:var v=document.getElementById("v"); //得到DOM对象
var $v=$(v); //转成jQuery对象
转换后,就可以任意使用jQuery的方法了
以下方法都正确:
$("#div").html();
$("#div")[0].innerTHML;
$("#div").eq(0)[0].innerHTML;
$("#div").get(0).innerHTML;
$(document.getElementById("div")).html()
平时在使用过程中可以在变量前面加$以区分DOM对象和jQuery对象,添加$的为jQuery对象,没有的则为DOM对象
js判断数组中是否存在某个元素(四种方法)
#方法一:利用indexOf
#不存在返回-1,存在返回第一次出现的索引
var arr = [100,20,50,58,6,69,36,45,78,66,45]
if(arr.indexOf(66)==-1){
console.log("不存在")
}else{
console.log("存在,索引是:",arr.indexOf(66))
}
#方法二:利用find
#它的参数是一个回调函数,所有数组元素依次遍历该回调函数,直到找出第一个返回值为true的元素,
#然后返回该元素,否则返回undefined。
var arr = [100,20,50,58,6,69,36,45,78,66,45]
arr.find(function(value,index,arr){
if(value==45){
console.log("存在",index)
}
}) #查找45,find会找出所有存在的45以及索引
#方法三:利用some
#some方法同样用于检测是否有满足条件的元素,如果有,则不继续检索后面的元素,直接返回true,
#如果都不符合,则返回一个false。用法与find相似,只是find是返回满足条件的元素,
#some返回的是一个Boolean值,从语义化来说,是否包含返回布尔值更贴切
let arr = [100,20,50,58,6,69,36,45,78,66,45]
// some
let result = arr.some(ele => ele === 45) //true
if (result) {
//do something...
};
#方法四:includes
#ES6新增的数组方法,用于检测数组是否包含某个元素,如果包含返回true,否则返回false,比较厉害的是,能直接检测NaN:
#优点 就不用说了,最简单的做法没有之一,不用回调,不用复杂的写法,一个方法直接搞定。
#缺点 是低版本浏览器支持不是很友好
let arr = [100,20,50,58,6,69,36,45,78,66,45,NaN]
// 法四
let flag = arr.includes(1100)
let flag1 = arr.includes(NaN)
console.log(flag,flag1)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库