Skip to content

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命令查看

  • 将本地仓库推送到远程仓库中(不推荐这种方式)
  • 配置远程服务器共钥
  • 检测是否配置成功
  • 克隆远程仓库

  • 注意:使用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 方法

  • callapply 方法不同,不会立即执行,会返回一个改变了 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,如果没有,则thiswindow
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 infor 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],将一系列值转换成数组
  • findfindIndex找出符合条件的第一个元素和下标
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