Appearance
git 操作
全局配置用户名邮箱
查看全局配置
创建本地仓库
查看文件状态
可简写为 git status -s
会展示更加精简的内容
开始跟踪文件
提交到 git 仓库进行管理
- 如果将已经提交
git
仓库的文件进行修改后,再查看文件状态会变成modified
状态
此时运行git add
就可以将已修改的文件重新提交到暂存区
- 提交后可运行
git commit -m
把暂存区文件提交到git
仓库管理
- 撤销操作(不建议)
- 用
git
仓库中保存的文件,覆盖工作区中指定的文件
- 用
- 一次提交多个文件到暂存区
- 即使是未跟踪的文件也会被直接提交到暂存区
- 可以跳过暂存区,直接提交到 git 仓库
- 但只能提交已经跟踪的文件
bash
git commit -am "提交信息" //相当于 git commit -a -m "提交信息"
忽略文件,在 git 仓库里创建一个
.gitignore
文件,在里面写正则就可以匹配文件选择性的忽略,忽略的文件不会被跟踪到查看历史提交信息
版本回退
回退后
log
命令就不能查看全部历史版本信息,这时需要用reflog
命令查看
- 将本地仓库推送到远程仓库中(不推荐这种方式)
- 使用 SSH 上传远程服务器(推荐这种方式)
- ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
- 配置远程服务器共钥
- 检测是否配置成功
克隆远程仓库
注意:使用
git clone
命令下载代码时,选择的协议,决定了将来提交代码的协议(https、SSH
)建议使用 SSH 协议克隆查看分支
决定团队协作
- 创建新分支
- 切换分支
- 快速创建并切换分支
- 合并分支
- 删除分支
- 冲突分支
- 将远程仓库创建分支
- 可以运行 git push 远程仓库名 本地分支名 根据提示推送到远程分支
将远程仓库
查看和修改远程传送协议
jquery
入口函数
html
<div></div>
js
//等待页面DOM加载完毕再执行,相当于原生js里的DOMContentLoaded
// $(document).ready(function(){
// $("div").hide();//隐藏元素
// });
//可简写为以下代码
$(function () {
$('div').hide()
})
对象转换
html
<div></div>
js
let div = document.querySelector('div')
let divj = $(div) //jQuery对象转化为DOM对象
$(div)[0].onclick = function () {
//jQuery对象转化为DOM对象
console.log(456)
}
隐式迭代
html
<style>
div {
width: 200px;
height: 200px;
background-color: #000000;
}
</style>
<div></div>
<div></div>
<div></div>
js
$('div').css('background-color', 'red') //通过隐式迭代修改所有div的样式,不需要像原生js里用循环修改
筛选选择器
- 父子选择器
jquery
添加事件
html
<style>
.grandfather {
width: 200px;
height: 200px;
}
.parent {
width: 200px;
height: 200px;
background-color: cadetblue;
}
.son {
width: 200px;
height: 200px;
background-color: orange;
display: none;
}
</style>
<div class="grandfather">
<div class="parent"></div>
</div>
<div class="son"></div>
js
$('.grandfather>.parent').mouseenter(function () {
//添加鼠标移入事件
$('.son').show() //显示元素
})
$('.grandfather>.parent').mouseleave(function () {
//添加鼠标离开事件
$('.son').hide()
})
jquery
排他思想
html
<button>点击</button>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<button>点击</button>
js
//利用jquery的隐式迭代循环给所有按钮添加点击事件
$('button').click(function () {
$(this).css('background-color', 'red')
//去除除自己以外的所有按钮的样式
$(this).siblings().css('background-color', '')
})
table 栏切换
html
<style>
div {
width: 200px;
height: 200px;
background-color: oldlace;
text-align: center;
line-height: 200px;
display: none;
}
.div1 {
display: block;
}
</style>
<button>点击1</button>
<button>点击2</button>
<button>点击3</button>
<button>点击4</button>
<button>点击5</button>
<button>点击6</button>
<div class="div1">div1</div>
<div class="div2">div2</div>
<div class="div3">div3</div>
<div class="div4">div4</div>
<div class="div5">div5</div>
<div class="div6">div6</div>
js
$('button').mouseenter(function () {
let index = $(this).index() //返回隐式迭代的索引,在这里就是返回所有按钮的索引
$(this).css('background-color', 'oldlace')
$(this).siblings().css('background-color', '')
$('div').eq(index).show()
$('div').eq(index).siblings('div').hide()
})
jquery
链式编程
- 利用链式编程可以将重复的代码简化,·达到优化的目的,上面的代码可简写为以下代码
js
$('button').mouseenter(function () {
let index = $(this).index()
$(this)
.css('background-color', 'oldlace')
.siblings()
.css('background-color', '')
$('div').eq(index).show().siblings('div').hide()
})
添加样式
html
<style>
div {
width: 200px;
height: 200px;
background-color: oldlace;
text-align: center;
line-height: 200px;
}
</style>
<div class="div6">div6</div>
js
$('div').css({
//样式操作,可以用对象添加多个样式
backgroundColor: 'red', //复合属性需要使用驼峰命名法
width: 400, //用对象添加样式时属性名可以不加引号
height: 400 //当属性值为数字时,属性值也可以不加引号
})
console.log($('div').css('width')) //可直接获取元素的css样式
类的操作
html
<style>
div {
width: 200px;
height: 200px;
background-color: oldlace;
text-align: center;
line-height: 200px;
}
.tog {
background-color: red;
}
.tog1 {
color: orange;
}
</style>
<div class="div6">div6</div>
js
$('div').addClass('tog') //追加类,不会影响之前的类名
$('div').removeClass('div6') //删除类
$('div').click(function () {
$('div').toggleClass('tog1') //切换类,有就删除,没有就添加
})
获取元素属性
html
<a href="javascript:;" aa="bb">无跳转</a> <input type="checkbox" checked />
js
console.log($('a').prop('href')) //获取元素属性
$('a').prop('href', '#') //修改属性值
console.log($('input').prop('checked')) //false
$('input').prop('checked', true) //修改属性值
$('a').attr('aa', '45') //修改自定义属性
console.log($('a').attr('aa')) //获取自定义属性
修改元素内容
js
html() //类似于原生的innnerhtml
text() //类似于原生的innnertext
val() //类似于原生的value
遍历元素 each 方法
html
<div>1</div>
<div>2</div>
<div>3</div>
js
//针对同一元素做不同操作,需要用到遍历元素。可以使用each方法遍历元素
$('div').each(function (index, item) {
console.log(index) //第一个参数是遍历的索引
console.log(item) //第二个参数是遍历的元素
})
遍历数据(任何对象包括数组)
js
//遍历对象
let obj = { name: '周杰伦', age: 45 }
$.each(obj, function (index, item) {
console.log(item) //对象的值
console.log(index) //对象的键
})
js
//遍历数组时
let arr = [1, 8, 0, 4]
$.each(arr, function (index, item) {
console.log(item) //数组的元素
console.log(index) //数组的下标
})
操作 DOM 元素
html
<div class="box">
<div class="box1"></div>
</div>
<div class="box3"></div>
js
//创建元素
var li = $('<p>1</p>')
//添加子元素
$('.box').append(li) //在内部添加并且放到内容后面
// $(".box").prepend(li);//在内部添加并且放到内容前面
//添加兄弟元素
var b = $('<b>1</b>')
// $(".box3").after(b);//在指定元素之后添加元素
$('.box3').before(b) //在指定元素之前添加元素
//删除元素
$('.box3').remove() //删除指定元素自身
// $(".box").empty();//删除指定元素的所有子元素
$('.box').html('') //删除指定元素的所有子元素
获取元素大小
html
<style>
div {
width: 200px;
height: 200px;
background-color: chocolate;
}
</style>
<div></div>
js
$('div').width(300) //设置宽度
console.log($('div').width()) //获取宽度
获取元素偏移
html
<style>
* {
margin: 0;
padding: 0;
}
.box2 {
position: absolute;
width: 200px;
height: 200px;
left: 10px;
top: 10px;
background-color: chocolate;
}
</style>
<div class="box2"></div>
js
$('.box2').offset({
//相对于页面文档设置
top: 30,
left: 30
}) //设置元素偏移
console.log($('.box2').offset()) //获取元素偏移,返回一个装有偏移量的对象
获取页面卷去的距离
html
<style>
* {
margin: 0;
padding: 0;
}
.box2 {
width: 200px;
height: 3000px;
background-color: chocolate;
}
</style>
<div class="box2"></div>
js
$(window).scroll(function () {
//页面滚动事件
$(document).scrollTop(300) //设置页面被卷去top的距离
console.log($(document).scrollTop()) //获取页面被卷去top的距离
})
利用 jq
完成返回顶部动画
html
<style>
* {
margin: 0;
padding: 0;
}
.box2 {
width: 200px;
height: 3000px;
background-color: chocolate;
}
button {
position: fixed;
bottom: 100px;
right: 50px;
opacity: 0;
transition: 1s;
}
</style>
<div class="box2"></div>
<button>返回顶部</button>
js
let hig = document.documentElement.clientHeight
$(window).scroll(function () {
//页面滚动事件
if ($(document).scrollTop() > hig) {
//当页面被就去的top值大于当前屏幕高度时显示回到顶部按钮
$('button').css('opacity', 1)
} else {
$('button').css('opacity', '')
}
})
$('button').click(function () {
//给回到顶部按钮添加点击功能
$('html,body').stop().animate(
{
//给html和body添加动画
scrollTop: 0
},
1000
)
})
电梯导航(案例)
html
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 200px;
height: 500px;
background-color: chocolate;
margin-top: 20px;
text-align: center;
line-height: 300px;
font-size: 30px;
}
button {
position: fixed;
bottom: 100px;
right: 50px;
opacity: 0;
transition: 1s;
}
ul {
position: fixed;
right: 200px;
top: 100px;
list-style: none;
}
li {
width: 50px;
height: 50px;
text-align: center;
line-height: 50px;
cursor: pointer;
background-color: lightgray;
margin-bottom: 10px;
}
</style>
<div class="box2">1</div>
<div class="box2">2</div>
<div class="box2">3</div>
<div class="box2">4</div>
<div class="box2">5</div>
<div class="box2">6</div>
<div class="box2">7</div>
<div class="box2">8</div>
<div class="box2">9</div>
<div></div>
<div></div>
<div></div>
<div></div>
<button>返回顶部</button>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
js
let hig = document.documentElement.clientHeight //计算当前屏幕的高度
let flag = true //设置节流阀,当点击li时不需要动态根据页面被卷去的距离给li添加样式
$(window).scroll(function () {
//页面滚动事件
if ($(document).scrollTop() > hig) {
//当页面被就去的top值大于当前屏幕高度时显示回到顶部按钮
$('button').css('opacity', 1)
} else {
$('button').css('opacity', '')
}
if (flag) {
//节流阀
//根据页面被卷去的距离动态给li添加样式
$('.box2').each(function (index, item) {
if ($('body,html').scrollTop() >= $(item).offset().top) {
$('li')
.eq(index)
.css('backgroundColor', 'orange')
.siblings()
.css('backgroundColor', 'lightgray')
}
})
}
})
$('button').click(function () {
//给回到顶部按钮添加点击功能
$('html,body').stop().animate({
//给html和body添加动画
scrollTop: 0
})
})
$('li').click(function () {
//给每个li添加点击事件
flag = false
//计算与当前里索引对应的div距离页面顶部的距离
let divTop = $($(this).parent().siblings().eq($(this).index())).offset().top
$('body,html')
.stop()
.animate(
{
//设置页面顶部的距离并添加动画
scrollTop: divTop
},
function () {
flag = true
}
) //当点击动画完成后打开节流阀
$(this)
.css('backgroundColor', 'orange')
.siblings()
.css('backgroundColor', 'lightgray')
})
购物车案例
html
<div>
<button class="cut">-</button>
<input type="text" value="0" />
<button class="plus">+</button>
<span>¥12.5元</span>
<b>¥0元</b><br /><br />
</div>
<div>
<button class="cut">-</button>
<input type="text" value="0" />
<button class="plus">+</button>
<span>¥50元</span>
<b>¥0元</b><br /><br />
</div>
<div>
<button class="cut">-</button>
<input type="text" value="0" />
<button class="plus">+</button>
<span>¥99元</span>
<b>¥0元</b>
</div>
<br /><br />
<div class="fullmoy">合计</div>
js
function sumDol() {
//计算合计金额
let fullmoy = 0
$('span').each(function (index, item) {
fullmoy += $(item).text().slice(1, -1) * $(item).siblings('input').val()
})
$('.fullmoy').html('合计 ' + fullmoy + ' 元') //添加计算完后的数据
}
$('.plus').click(function () {
//给所有的加号添加点击事件
let num = $(this).siblings('input').val() //获取当前input的value值
let dol = $(this).siblings('span').html() //获取当前span里的价格
num++ //自增加一
$(this).siblings('input').val(num) //将自增的结果添加到input的value值
// 计算小计金额
let moy = num * parseFloat($(this).siblings('span').text().slice(1, -1))
$(this)
.siblings('b')
.text('¥' + moy + '元')
//计算合计金额
sumDol() //调用函数计算合计金额
})
$('.cut').click(function () {
//给所有的减号添加点击事件
let num = $(this).siblings('input').val() //获取当前input的value值
if (num == 0) {
//判断当前input的value值是否等于0
return false
}
num--
$(this).siblings('input').val(num)
// 计算小计金额
let moy = num * parseFloat($(this).siblings('span').text().slice(1, -1)) //
$(this)
.siblings('b')
.text('¥' + moy + '元')
//计算合计金额
sumDol() //调用函数计算合计金额
})
//当input值发生变化时,计算当前的小计金额
$('input').change(function () {
let moy =
parseInt($(this).val()) *
parseFloat($(this).siblings('span').text().slice(1, -1)) //计算小计
$(this)
.siblings('b')
.text('¥' + moy + '元') //添加计算完的金额
sumDol()
})
on 绑定事件
- 只需给父元素绑定点击事件实现触发子元素事件
html
<ul>
<li>11111</li>
<li>22222</li>
<li>33333</li>
</ul>
js
// 实现事件委托
$('ul').on('click', 'li', function () {
//给ul添加点击事件,利用冒泡传递,实现点击li执行回调函数
console.log(11)
})
- 可以给未来动态创建的元素绑定事件
html
<ul></ul>
js
// 可以给未来动态创建的元素绑定事件
$('ul').on('click', 'li', function () {
console.log(11)
})
let li = $('<li>111111</li>')
$('ul').append(li)
解绑事件和单次触发
html
<p>45646544</p>
<ul>
<li>11111111</li>
<li>21111111</li>
<li>3333333</li>
</ul>
js
$('ul').on('click', 'li', function () {
console.log('点击了li')
})
$('ul').on('mouseenter', function () {
console.log('yidong了li')
})
//事件解绑
// $("ul").off();//解除元素身上的所有事件
// $("ul").off("click");//解除元素身上指定事件
$('ul').off('click', 'li') //解除元素的事件委托
$('p').one('click', function () {
//只能触发一次
console.log(123123)
})
自动触发事件
html
<input type="text" />
js
$('input').focus(function () {
$('input').val('点击')
})
// $("input").focus();//自动触发事件,但会触发浏览器默认行为
$('input').triggerHandler('focus') //自动触发事件,不会触发浏览器默认行为
jquery
插件
利用插件可以快速实现某些功能
github
网站
备忘录
html
<style>
li {
list-style: none;
}
.myred {
color: orangered;
}
input {
outline: none;
}
</style>
<input type="text" class="pint" />
<span class="myred"></span>
<p class="noFinish">正在进行</p>
<ul class="noFinish_ul"></ul>
<hr />
<p class="Finish">已完成</p>
<ul class="Finish_ul"></ul>
js
let arr = []
let myLocation = JSON.parse(sessionStorage.getItem('title')) //获取本地存储的数据
if (myLocation) {
//当页面重新加载后重新渲染页面数据
$.each(myLocation, function (index, item) {
var li = $('<li></li>').html(
"<input type='checkbox'>" +
'<b>' +
item.title +
'</b>' +
'<button>移出</button>'
) //创建元素
$(li).attr('myi', index) //当页面重新加载后重新添加自定义属性
if (item.done == false) {
$('.noFinish_ul').prepend(li) //添加元素
} else {
$('.Finish_ul').prepend(li) //添加元素
$('.Finish_ul>li>input').prop('checked', 'true')
}
})
}
$('.pint').keyup(function (e) {
if (
$('.pint').val() == '' ||
$('.pint').val() == 'undefined' ||
$('.pint').val() == 'null'
) {
$('span').html('输入的内容不合法')
} else if (e.keyCode == 13) {
let myLocation6 = JSON.parse(sessionStorage.getItem('title')) //获取本地存储的数据
arr.length = 0 //清空数组
if (myLocation6) {
$.each(myLocation6, function (index, item) {
arr.push(item)
})
}
arr.push({
title: $('.pint').val().trim(),
done: false
}) //将输入的内容添加到数组中保存
sessionStorage.setItem('title', JSON.stringify(arr)) //将输入的内容添加到本地存储中保存
var li = $('<li></li>').html(
"<input type='checkbox'>" +
'<b>' +
$('.pint').val() +
'</b>' +
'<button>移出</button>'
)
$(li).attr('myi', JSON.parse(sessionStorage.getItem('title')).length - 1) //给新创建的li添加自定义属性索引
$('.noFinish_ul').prepend(li) //添加元素
$('.pint').val('') //添加完后清空input
} else if ($('.pint').val() != '') {
$('span').html('')
}
})
// 给未完成任务下的按钮添加删除功能
$('.noFinish_ul').on('click', 'button', function () {
let myLocation1 = JSON.parse(sessionStorage.getItem('title')) //获取本地存储的数据
let index = $(this).parent().attr('myi') //获取当前点击按钮的li的自定义索引
$(this).parent().remove() //删除当前li
myLocation1.splice(index, 1) //根据当前点击按钮的li的自定义索引删除数据
sessionStorage.setItem('title', JSON.stringify(myLocation1)) //将最新删除后的数据重新保存到本地
})
// 给已完成任务下的按钮添加删除功能
$('.Finish_ul').on('click', 'button', function () {
let myLocation4 = JSON.parse(sessionStorage.getItem('title')) //获取本地存储的数据
let index = $(this).parent().attr('myi') //获取当前点击按钮的li的自定义索引
$(this).parent().remove() //删除当前li
myLocation4.splice(index, 1) //根据当前点击按钮的li的自定义索引删除数据
sessionStorage.setItem('title', JSON.stringify(myLocation4)) //将最新删除后的数据重新保存到本地
})
//通过事件代理方式给未完成模块下的任务li添加事件
$('.noFinish_ul').on('click', 'input', function () {
$('.Finish_ul').prepend($(this).parent()) //当点击进行中的多选框后把当前li移动到已完成模块下
let myLocation2 = JSON.parse(sessionStorage.getItem('title')) //获取本地存储的数据
let bValue2 = $(this).siblings('b').html() //获取b标签里的数据
$.each(myLocation2, function (index, item) {
//遍历本地存储的数据
if (bValue2 == item.title) {
//找出当前点击数据对应的本地存储的数据
myLocation2[index].done = true
sessionStorage.clear()
sessionStorage.setItem('title', JSON.stringify(myLocation2)) //将最新修改后的数据重新保存到本地
}
})
})
//通过事件代理方式给已完成模块下的任务li添加事件
$('.Finish_ul').on('click', 'input', function () {
$('.noFinish_ul').prepend($(this).parent()) //当点击已完成的多选框后把当前li移动到进行中模块下
let myLocation3 = JSON.parse(sessionStorage.getItem('title')) //获取本地存储的数据
let bValue3 = $(this).siblings('b').html() //获取b标签里的数据
$.each(myLocation3, function (index, item) {
//遍历本地存储的数据
if (bValue3 == item.title) {
//找出当前点击数据对应的本地存储的数据
myLocation3[index].done = false
sessionStorage.clear()
sessionStorage.setItem('title', JSON.stringify(myLocation3)) //将最新修改后的数据重新保存到本地
}
})
})
echarts
数据可视化项目
网址:echarts.apache.org
边框图片
- 柱状图参数
- 雷达图配置
原型链解析
原型对象
new 的执行过程
tab 栏切换(面向对象方式)
html
<style>
* {
margin: 0;
padding: 0;
user-select: none;
}
ul li {
list-style: none;
}
main {
width: 960px;
height: 500px;
border-radius: 10px;
margin: 50px auto;
}
main h4 {
height: 100px;
line-height: 100px;
text-align: center;
}
.tabsbox {
width: 900px;
margin: 0 auto;
height: 400px;
border: 1px solid lightsalmon;
position: relative;
}
nav ul {
overflow: hidden;
}
nav ul li {
float: left;
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
border-right: 1px solid #ccc;
position: relative;
}
nav ul li.liactive {
border-bottom: 2px solid #fff;
z-index: 9;
}
#tab input {
width: 80%;
height: 60%;
}
nav ul li span:last-child {
position: absolute;
user-select: none;
font-size: 12px;
top: -18px;
right: 0;
display: inline-block;
height: 20px;
}
.tabadd {
position: absolute;
/* width: 100px; */
top: 0;
right: 0;
}
.tabadd span {
display: block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border: 1px solid #ccc;
float: right;
margin: 10px;
user-select: none;
}
.tabscon {
width: 100%;
height: 300px;
position: absolute;
padding: 30px;
top: 50px;
left: 0px;
box-sizing: border-box;
border-top: 1px solid #ccc;
}
.tabscon section,
.tabscon section.conactive {
display: none;
width: 100%;
height: 100%;
}
.tabscon section.conactive {
display: block;
}
.fisrstnav input,
.tabscon input {
outline: none;
/* border: none; */
}
@font-face {
font-family: 'iconfont';
src: url('./iconfont/iconfont.eot?t=1553960438096');
/* IE9 */
src: url('./iconfont/iconfont.eot?t=1553960438096#iefix') format('embedded-opentype'),
/* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK4AAsAAAAABmwAAAJrAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp4fwE2AiQDCAsGAAQgBYRtBzAbpQXIrrApw71oi3CCOyzEy8RvE4yIN8TD036/zp03qCYRjaJZNBFFS/gREoRGipQKofjuNrb+9XbTqrmXcqWzfTRDqFqWkhAJzYToaE6LQ7Q30CirRqSKMnj58DdIdrNAdhoTQJa5VGfLrtiAy+lPoAcZdUC57UljTR4TMAo4oL0xiqwYG8YueIHPCdTqYajty/t+bUpmrwvEnUK42lQhLMssVy1UNhzN4kmF6vSQVvMY/T5+HEU1SUXBbti7uBBrx++cgqJULp0GhAgBna5AgSkgE0eN6R1NwTitNt0yAI5VG7wr/8AljmoX7K+zq+tBF1Q8k9JTPWp1AjnJDgCzmM3bU0V31dsvV3M2eC6fHjaGfX/qS7U5Gr58vj6uD0bgxudyrV/OtHHyP+NZnpO1txbktjdY+3FB61+7nxeOzq8niGYnRwT3v3aZxeXf6rrNxl5//49WlEtZUUL1Pj3Bv1EO7MuG2namrCkbvcnApLUJtWpRhv2tzlRLx43kQ7WO2/FW6c5QqDZEZnYKFeosoVK1NdSa5E/XaVM1Ra7BhAEQmk0kjV5QaLbIzG5U6HRRqTkK1DqJtivrjMT1zJaNnIsihAiyQE3JdbszcW0Xiadzdl4d8UO0HSUGNDNXzl2hifYSO5pPjrorgdjUAAavoa5TKDZVUXD3kuuOOzh70fShvUiN2owtNsRxIREIIiATUCYpGO2aqXy/CxEeHcfuaKrLDiGbQ5kcEMsNIK8M5qCmR3mn8RFHOpcECBtlAAwWIZ2OAqV5kQoJXHvShORYBzrDZKhhb3uT8QPlrA3bmsKZV6i89DiTV2o1AAAA')
format('woff2'),
url('./iconfont/iconfont.woff?t=1553960438096') format('woff'), url('./iconfont/iconfont.ttf?t=1553960438096')
format('truetype'),
/* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('./iconfont/iconfont.svg?t=1553960438096#iconfont') format('svg');
/* iOS 4.1- */
}
.iconfont {
font-family: 'iconfont' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-guanbi:before {
content: '\e676';
}
</style>
<main>
<h4>Js 面向对象 动态添加标签页</h4>
<div class="tabsbox" id="tab">
<!-- tab 标签 -->
<nav class="fisrstnav">
<ul>
<li class="liactive">
<span>测试1</span><span class="iconfont icon-guanbi"></span>
</li>
<li><span>测试2</span><span class="iconfont icon-guanbi"></span></li>
<li><span>测试3</span><span class="iconfont icon-guanbi"></span></li>
</ul>
<div class="tabadd">
<span>+</span>
</div>
</nav>
<!-- tab 内容 -->
<div class="tabscon">
<section class="conactive">测试1</section>
<section>测试2</section>
<section>测试3</section>
</div>
</div>
</main>
js
var that
class Tab {
constructor(id) {
//获取tab栏元素
that = this //保存this
this.main = document.querySelector(id)
this.ul = document.querySelector('ul')
this.tabscon = document.querySelector('.tabscon')
this.add = document.querySelector('.tabadd')
this.innt()
}
innt() {
//初始化对象,给所有li绑定点击事件
this.updatenode()
this.add.onclick = this.addtab //给添加按钮添加点击事件
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i
this.lis[i].onclick = this.togtab //给所有li添加点击事件
this.remove[i].onclick = this.removetab //给所有删除按钮点击事件
this.spans[i].ondblclick = this.edittab
this.div[i].ondblclick = this.edittab
}
}
togtab() {
//切换tab栏功能
that.clealClass() //清除其他元素的样式,排他
this.className = 'liactive' //给当前li添加样式
that.div[this.index].className = 'conactive' //给当前div添加样式
}
clealClass() {
//利用排他思想清除其他
for (var i = 0; i < this.lis.length; i++) {
//清空样式
this.lis[i].className = ''
this.div[i].className = ''
}
}
updatenode() {
//获取当前页面需要的所有元素
this.spans = document.querySelectorAll('.fisrstnav li span:nth-of-type(1)') //获取所有liactive里
this.remove = document.querySelectorAll('.icon-guanbi') //获取所有删除按钮
this.lis = document.querySelectorAll('ul>li') //获取所有li
this.div = document.querySelectorAll('.tabscon>section') //获取所有div
}
addtab() {
//添加元素功能
if (that.lis.length < 8) {
//判断是否创建的li超过了ul的宽度,超过了则不再创建新的元素
that.clealClass()
// 添加li元素
let li = `<li class="liactive"><span>测试${
that.lis.length + 1
}</span><span class="iconfont icon-guanbi"></span></li>`
that.ul.insertAdjacentHTML('beforeend', li) //insertAdjacentHTML可以将元素字符串添加到指定位置
// 添加div
let div = `<section class="conactive">测试${
that.lis.length + 1
}</section>`
that.tabscon.insertAdjacentHTML('beforeend', div)
that.innt() //重新初始化获取DOM元素
} else {
alert('添加的元素过多!')
}
}
removetab(e) {
//删除元素功能
e.stopPropagation() //阻止冒泡排序,防止点击右上角删除按钮触发li的点击事件
let index = this.parentNode.index //记录当前点击的li的索引
that.lis[index].remove() //根据索引删除对应li
that.div[index].remove() //根据索引删除对应div
that.innt() //重新初始化获取DOM元素
if (document.querySelector('.liactive')) return //当页面上存在已经选中的li时,删除后选中的li不变
//实现删除一个li前面的一个li会自动获取点击样式
index-- //将索引减一
that.lis[index] && that.lis[index].click() //判断是否到达极限位置,当索引为0时将不执行点击事件
//当索引为0时判断前一个li是否存在(判断是否是页面上最后一个li),存在就执行前一个li的点击事件
that.lis[index + 1] && that.lis[index + 1].click()
}
edittab() {
//修改内容功能
this.innerHTML = `<input type="text" value="${this.innerHTML}">` //读取当前选中元素的内容
let value = this.querySelector('input') //获取当前元素内的input
value.select() //获取光标后自动全选input元素内容
value.onblur = function () {
//当input失去焦点
this.parentNode.innerHTML = this.value //将input里的内容添加到父元素中
value.remove() //删除创建的input
}
}
}
new Tab('#tab')
- 利用面向对象思想将 tab 栏整体抽取为一个对象
- tab 栏共分为 4 个功能:添加、删除、切换、修改,分别封装为 4 个对象
- 扩展
insertAdjacentHTML
可以将 DOM 元素字符串添加到指定位置 - 扩展
value.select();
获取光标后自动全选 input 元素内容
bind 方法
- 和
call
、apply
方法不同,不会立即执行,会返回一个改变了this
指向后的新函数
let 关键字
- 会预处理,有变量提升,但是不能提前使用提升的变量
- 全局变量提升
- 会创建一个变量对象(
script
)用来收集全局作用域下 let 定义的变量,但是没有赋值
- 会创建一个变量对象(
- 局部变量提升
- 会将
var let
定义的变量全部放到当前函数的变量对象中
- 会将
- 全局变量提升
解构赋值
js
let obj = { name: 12, age: 45 }
let { name, age, sex } = obj //这样可以快速获取我们想要的数据,按需获取
console.log(name, age) //12 45
console.log(name) //12
console.log(sex) //undefined
js
//解构赋值的应用
let obj = [0, 2, 6]
let str = { name: 'zjl', age: 56 }
function f1({ name, age }) {
console.log(name) //zjl
console.log(age) //56
}
f1(str)
- 数组解构
js
let obj = [0, 2, 6]
let [a, b, c] = obj
console.log(a, b, c) //0 2 6
模板字符串
- 模板字符串:简化字符串拼接
- 模板字符串必须用``包含
- 变化的部分使用
${xxx}
定义
js
let str = { name: 'zjl', age: 56 }
let ssr = `我的名字是${str.name},年龄是${str.age}`
console.log(ssr) //我的名字是zjl,年龄是56
- 一些新写法
js
let username = 45666666
let age = 4567777776
let obj = {
// username:username,
// age:age,
username, //同名的属性可省略 key和value一样的时候
age,
// show:function(){
// console.log(456);
// }
show() {
//省略函数的function和冒号
console.log(456)
}
}
console.log(obj)
obj.show()
- 还可以写入三元运算符
html
<style>
div {
width: 200px;
height: 200px;
background-color: #00b4ff;
}
.black {
border: #000000 solid 10px;
}
.red {
border: red solid 10px;
}
</style>
<div></div>
js
let obj = {
flag: false
}
let div = document.querySelector('div')
div.className = `${obj.flag ? 'black' : 'red'}`
箭头函数
js
let fun2 = function () {
//传统函数
console.log(123)
}
fun2()
//当箭头函数没有形参的时候小括号不能省略
let fun = () => console.log(4456)
fun()
//当箭头函数有一个形参的时候小括号可以省略
let fun1 = a => console.log(4456 + ',' + a)
fun1(222)
//当箭头函数有多个形参的时候小括号不能省略
//当箭头函数的函数体只有一条语句的时候大括号可以省略
//省略大括号函数会自动返回当前语句或者表达式的结果
let fun3 = (a, b) => a + b
console.log(fun3(222, 'op')) //222op
//当函数体有多条语句时大括号不能省略
let fun3 = (a, b) => {
a + b
console.log(456)
}
fun3()
- 箭头函数的特点
- 箭头函数不能用作构造函数,因为构造函数的
this
必须指向它的实例 - 箭头函数没有自己的
this
,箭头函数的this
不是调用的时候决定的,而是在定义的时候处在的上下文对象就是它的this
- 扩展理解:箭头函数的
this
看外层的是否有函数,如果有外层函数的this
就是内部箭头函数的this
,如果没有,则this
是window
- 箭头函数不能用作构造函数,因为构造函数的
js
let btn1 = document.querySelector('.btn1')
let btn2 = document.querySelector('.btn2')
btn1.onclick = function () {
console.log('传统函数')
console.log(this) //btn1
}
btn2.onclick = () => console.log(this) //window
html
<button class="btn1">传统函数</button> <button class="btn2">箭头函数</button>
...
运算符
- 比函数里的
arguments
更好用
js
//类数组没有数组的方法(push、pop)但是可以像数组一样通过中括号和下标获得里面的数据
function fn(...ec) {
console.log(arguments) //得到一个类数组
console.log(ec) //得到一个数组
}
fn(1, 2, 5)
js
function fn(a, ...ec) {
console.log(ec) //[2, 5]
}
fn(1, 2, 5)
- 还可以用来扩展
js
//在arr1里快速在自定位置插入arr2
let arr1 = [1, 5]
let arr2 = [4, 8, 9]
let arr3 = [1, ...arr2, 5]
console.log(arr3) //[1, 4, 8, 9, 5]
ES6
中添加了一种原始数据类型Symbol
Symbol
属性对应的值是惟一的,解决命名冲突问题Symbol
值不能与其他数据进行计算,包括同字符串拼接for in
、for of
遍历时不会遍历Symbol
属性
js
let symbol = Symbol('one')
let symbol2 = Symbol('tow')
console.log(Symbol.iterator) //Symbol(Symbol.iterator) 对象的Symbol.iterator指向该对象的默认遍历器方法
- Iterator 遍历器
ES6
创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费
原生具备 iterator 接口的数据(可用 for of 遍历)
- Array
- arguments
- set 容器
- map 容器
- String
- ...
- js
// let arr = [1,5,9,4,5]; // for(let item of arr){//利用for of循环遍历数组 // console.log(item); // } let arr = 'asdadadadada' for (let item of arr) { //利用for of循环遍历字符串 console.log(item) }
获取对象键值对数量
js
let obj = { name: 'zhoujielun', age: 45 }
console.log(Object.keys(obj)) //返回一个数组,里面装着obj的所有键
console.log(Object.keys(obj).length) //这时调用数组的length属性就可以知道对象有多少个键值对,相当于对象的长度
class 类
js
class Person {
//定义一个类
//类的构造方法
constructor(name, age) {
//ES6简写函数,省略了function关键字
this.name = name
this.age = age
}
//类的一般方法
showinfo() {
console.log(123)
}
}
let person = new Person('周杰伦', 43) //创建一个实例,和构造函数类似
//类的构造方法和类的一般方法都在实例的原型对象上
console.log(person)
person.showinfo()
- 类的继承
js
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
showinfo() {
console.log(123)
}
}
class Son extends Person {
//继承
constructor(name, age) {
//super做的事情:1.调用父类的构造方法。2.改变父类构造方法的this指向为子类的实例
super(name, age) //继承父类时必须调用super构造方法
}
}
let son = new Son('周杰伦', 34)
console.log(son)
son.showinfo() //能调用父类的方法,此时子类的原型对象充当父类的实例,这就是继承的原理
ES6
方法
Array.of
将一系列值转换成数组
js
console.log(Array.of(1, 'tug', true)) //[1, "tug", true],将一系列值转换成数组
find
和findIndex
找出符合条件的第一个元素和下标
js
let arr = [1, 5, 9, 4, 25]
let result = arr.find(function (item, index) {
//找出第一个满足条件的元素,在这里是找出第一个大于5的数据
return item > 5
})
let result2 = arr.findIndex(function (item, index) {
//找出第一个满足条件的元素的下标,在这里是找出第一个大于5的下标
return item > 5
})
console.log(result) //9
console.log(result2) //2
Object.assign
对象克隆
js
let target = {}
let sources1 = { name: 'kobe', age: 43 }
let sources2 = { age: 43 }
//可将多个对象中的数据克隆到源对象中,相同的数据会覆盖
let result = Object.assign(target, sources1, sources2)
console.log(result) //{name: "kobe", age: 43}
console.log(target) //{name: "kobe", age: 43} 源对象中的数据改变
__proto__
修改对象的隐式原型对象
js
let sources1 = { name: 'kobe', age: 43 }
let obj = {}
obj.__proto__ = sources1 //ES6可以直接修改隐式原型对象,这时obj的隐式原型对象上就会有sources1的属性
console.log(obj)
Set 容器
- Set 容器:无序不可重复的多个 value 的集合体
js
let alet arr = [4,5,0,2,5,6,1,6,9,5];
let set =new Set(arr);//set集合只能传递一个数组,利用set集合可以完成数组去重
console.log(set);
set.add(66);//添加一个数据
console.log(set);
set.delete(4);//删除一个数据
console.log(set);
console.log(set.has(9));//true 判断是否存在一个值
set.clear();//清空容器
console.log(set.size);//返回容器内数据的个数g(set);
- 利用 Set 容器封装一个数组去重方法
js
let arr = [4, 5, 0, 2, 5, 6, 1, 6, 9, 5]
//数组去重
// function uniqarr(arr){
// let set =new Set(arr);
// let arr2=[...set];
// return arr2;
// }
// 利用箭头函数可将上面代码优化为以下代码
uniqarr = arr => [...new Set(arr)]
console.log(uniqarr(arr))
for of 循环
- for of 循环可用于遍历数组、Set 容器、Map 容器、字符串、伪数组
js
let arr = [4, 5, 0, 2, 5, 6, 1, 6, 9, 5]
let set = new Set(arr)
//利用for of循环遍历set容器
for (let item of set) {
console.log(item)
}
封装一个检测数据类型的方法
- 对象属性查询和对象调用
toString
方法的一些细节
js
let obj = { name: 'zhoujielun' }
let obj2 = { age: 45 }
let obj3 = {}
obj3[obj] = 4 //此时会把obj变量转换为字符串[object Object],相当于给obj3添加了一个这样的键值对 [object Object]: 4
obj3[obj2] = 5 //此时同理相当于给obj3添加了一个这样的键值对 [object Object]: 5
console.log(obj3[obj]) //5 此时等同于查询obj3里的[object Object]属性的值
// 当对象调用toString()方法时返回值是数据的类型
console.log(obj.toString()) //[object Object]
- 当数组调用
toString
时会返回数组元素的字符串,可以发现数组和对象调用toString
方法不一样
js
let arr = [1, 5, 6]
//数组调用的是数组自己原型上的toString方法而不是调用对象原型上的toString方法
console.log(arr.toString()) //1,5,6
- 封装方法
js
//对象上的tostring方法会返回数据的数据类型,借用这一点可以封装一个检测数据类型的方法
function checkoutType(target) {
return Object.prototype.toString.call(target).slice(8, -1) //将传入的参数this强制改为Object.prototype调用对象的toString方法
}
// //可简写为以下代码
// // checkoutType = (target) => Object.prototype.toString.call(target).slice(8, -1);
console.log(checkoutType([4]))
ES7
方法
js
console.log(3 ** 3) //27 指数运算符 幂
let arr = [1, 2, 3]
console.log(arr.includes(1)) //ture 判断数组中是否包含指定数据
console.log(arr.includes(4)) //false
闭包
产生闭包(条件)
- 函数嵌套、内部函数引用外部函数的局部变量、使用内部函数
闭包是什么
- 所谓闭包就是一个引用关系,该引用关系存在于内部函数中,引用的是外部函数的变量
js
function fun() {
var a = 123
function fun2() {
console.log(a)
}
return fun2
}
var fun2 = fun()
fun2() //fun函数执行完本该销毁,但此时fun2又执行所以就能访问到变量a就形成了闭包
闭包的作用
- 使外部作用域可以去操作内部的变量
闭包的特点及清除
- 优点:延长外部变量对象的生命周期
- 缺点:容易占内存,使用完尽量清除
js
function fun() {
var a = 123
function fun2() {
console.log(a)
}
return fun2
}
var fun2 = fun()
fun2()
fun2 = null //只要使内部函数没有指针指向,那么就可以清除闭包
闭包面试题
- 利用闭包实现点击每个
li
能找到当前li
的索引
html
<ul>
<li>1111111</li>
<li>2222222</li>
<li>3333333</li>
<li>4444444</li>
</ul>
js
var li = document.querySelectorAll('li')
for (var i = 0; i < li.length; i++) {
;(function (i) {
li[i].onclick = function () {
console.log(i)
}
})(i)
}
浅拷贝
js
var obj = {
name: 'zhang',
age: 12,
mag: {
sex: 'man'
}
}
var o = {}
//浅拷贝,这里mag对象的地址拷贝到o中
Object.assign(o, obj) //利用 assign 方法将obj对象的属性拷贝到o对象中(浅拷贝)
console.log(o)
深拷贝
js
var obj = {
name: 'zhang',
age: 12,
mag: {
sex: 'man'
},
ar: ['嘻嘻嘻', 1]
}
var o = {}
//封装函数实现深拷贝
function deepCopey(target, souse) {
for (var k in souse) {
if (souse[k] instanceof Array) {
//判断源数据是否为数组
target[k] = [] //给目标数据创建空数组
deepCopey(target[k], souse[k]) //调用函数本身克隆数据
} else if (souse[k] instanceof Object) {
target[k] = {}
deepCopey(target[k], souse[k])
} else {
target[k] = souse[k] //如果不是复杂数据类型直接克隆
}
}
}
deepCopey(o, obj)
console.log(o)
作用域
作用域分类
- 静态作用域(词法作用域):JavaScript
- 特征:词法作用域规定作用域在代码定义的时候就决定了,而不是看调用的时候
- 动态作用域是在代码执行的时候决定的
- 动态作用域:bash