todolist

1.todolist实现

html页面

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>todolist</title>
  <link rel="stylesheet" href="./style/reset.css">
  <link rel="stylesheet" href="./style/main.css">
  <style>
    .todoed li{
      width: 300px;
    }
  </style>
</head>

<body>
  <div class="header">
    <span>工作任务</span>
    <span><input type="text" id="todotitle"></span>
  </div>
  <h3>正在进行中</h3>
  <ul class="todoing">
    
  </ul>
  <h3>已完成工作</h3>
  <ul class="todoed">
    
  
  
  </ul>
  <script src="./js/jquery.js"></script>
  <script src="./js/layer.js"></script>
  <script src="./js/Store.js"></script>
  <script src="./js/MyJson.js"></script>
  <script src="./js/moment.js"></script>
  <script src="./js/main.js"></script>
</body>

</html>
main.js
const store = new Store();
const key = 'todo';
const todoedKey = 'todoed';


$(function () {

  //获取光标移动数据
  $('#todotitle').blur(function () {
    const value = $.trim($(this).val());
    if (value !== '') $(this).val('');
    setValue(key, value);
  })

  //获取键盘事件的数据
  $('#todotitle').keydown(function (e) {
    if (e.keyCode === 13) {
      const value = $.trim($(this).val());
      if (value !== '') $(this).val('');
      setValue(key, value);
    }

    // $('todo li').remove();
    // let todoListData = getStoreData(key);
    // getListShow(todoListData);
  })


  //渲染
  let todoListData = getStoreData(key);
  //console.log(todoListData,"2222222");
  getListShow(todoListData);

  let todoedListData = getStoreData(todoedKey);
  getListShow2(todoedListData);


  //委托修改任务状态
  $('.todoing').on('change', 'input', function () {
    if ($(this).prop('checked')) {
      $(this).parents('li').remove();
      let todoedData = getStoreData(todoedKey);
      let tmpData = todoListData[$(this).val()];
      tmpData.edt = moment().format('YYYY-MM-DD HH-mm-ss');
      todoedData.unshift(tmpData);

      //转为json字符串存储在localstorage中
      todoedData = MyJson.stringify(todoedData);
      store.set(todoedKey, todoedData);

      //删除任务
      todoListData.splice($(this).val(), 1);
      let tmpTodoListData = MyJson.stringify(todoListData);
      store.set(key, tmpTodoListData); //处理好的数据存储

      //渲染
      $('.todoed li').remove();
      let todoListData1 = getStoreData(todoedKey);
      getListShow2(todoListData1);


      layer.msg('success', { icon: 1, time: 1000 });

    }
  })






  //删除正在进行的任务
  $('.todoing').on('click', '.del', function () {
    let self = $(this);
    let index = self.attr('value');

    layer.confirm('您真要删除?', {
      btn: ['确定', '再想一下']
    }, function () {
      let todoListData = getStoreData(key);
      todoListData.splice(index, 1);
      self.parents('li').remove();
      store.set(key, MyJson.stringify(todoListData));
      getListShow(todoListData);
      layer.msg('success', { icon: 1, time: 1000 })
    });
  })

  //删除完成的任务
  $('.todoed').on('click', '.del', function () {
    let self = $(this);
    let index = self.attr('value');

    layer.confirm('您真要删除?', {
      btn: ['确定', '再想一下']
    }, function () {
      let todoedListData = getStoreData(todoedKey);
      todoedListData.splice(index, 1);
      self.parents('li').remove();

      store.set(todoedKey, MyJson.stringify(todoedListData));
      //渲染
      $('.todoed li').remove();
      let todoListData1 = getStoreData(todoedKey);
      getListShow2(todoListData1);

      layer.msg('success', { icon: 1, time: 1000 })
    });
  })



})

function getListShow(todoListData) {

  if (Array.isArray(todoListData)) {
    $.each(todoListData, function (index, item) {
      let li = $(`<li>
        <span>
          <input class='setState' value='${index}' type="checkbox">
    </span>
          <span>${item.title} -- ${item.sdt}</span>
          <span value='${index}' class='del'>
            删除
    </span>
    </li>`
      )
      $('.todoing').prepend(li)
    })
  } else {

    let currIndex = $('.todoing li').length;
    console.log(currIndex);
    let li = $(`<li>
    <span>
      <input class='setState' value='${currIndex}' type="checkbox">
    </span>
    <span>${todoListData.title} -- ${todoListData.sdt}</span>
    <span value='${currIndex}' class='del'>
      删除
    </span>
    </li>`)
    $('.todoing li:first').before(li);
    //console.log("11111111");

  }
}



function getListShow2(todoListData) {

  if (Array.isArray(todoListData)) {
    $.each(todoListData, function (index, item) {
      let li = $(`<li>
      
          <span>${item.title} -- ${item.sdt}</span>
          <span value='${index}' class='del'>
            删除
    </span>
    </li>`
      )
      $('.todoed').prepend(li)
    })
  } else {

    let currIndex = $('.todoing li').length;
    console.log(currIndex);
    let li = $(`<li>
  
    <span>${todoListData.title} -- ${todoListData.sdt}</span>
    <span value='${currIndex}' class='del'>
      删除
    </span>
    </li>`)
    $('.todoed li:first').before(li);
    //console.log("11111111");

  }
}

//存储数据
function setValue(key, value) {
  if (value) {
    let data = getStoreData(key);
    let todoData = {
      title: value,
      sdt: moment().format('YYYY-MM-DD HH:mm:ss'),
      edt: ''
    }
    data.unshift(todoData);
    let tmpdata = MyJson.stringify(data);
    store.set(key, tmpdata);
    getListShow(todoData);

    layer.msg('success', { icon: 1, time: 1000 })
  }
}
function getStoreData(key) {

  return store.get(key) ? MyJson.parse(store.get(key)) : []
}

2.作用域与闭包

2.1作用域简单介绍

全局作用域只有一个,每个函数又都有作用域(环境)。es6+多了一个块级作用域。
作用域链只向上查找,找到全局window即终止,应该尽量不要在全局作用域中添加变量。
函数被执行后其环境变量将从内存中删除,函数每次调用都会创建一个新作用域

function count() {
  let total = 0;
  console.log(total)
  return total
}
count();

//如果子函数被使用时父级环境将被保留  -- 闭包;
function fn() {
  let n = 1;
  return function() {
      console.log(n++);
  };
}
let a = fn()
a()
//在闭包情况下若函数一直被调用,则局部变量不会被释放
  function fn() {
      let n = 1
      let data = []
      
      return function () {
        console.log(n++)
      }
    }
    let method = fn()
    method() //1
    method() //2
    method() //3
    method() //4

2.2 块级作用域

es6+以后有
块级作用域:if while for 里的花括号
var没有块级作用域

2.3 闭包

闭包是函数运行的一种机制,函数执行会形成一个私有作用域(上下文),如果私有作用域的某些内容被私有作用域以外的一些事物(如:变量/事件绑定等)所占用,则当前私有作用域不能被出栈释放。创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。

闭包的作用:

1.保护上下文中的私有变量与外界的变量互不影响
2.上下文中的私有变量和值都会被保存

闭包缺点:

会导致栈内存太大,页面渲染变慢,性能受到影响

闭包基本方法
function fn() {
  let n = 1;
  return function() {
      console.log(++n);
  };
}
let a = fn()
a()

//==============================================

let lessons = [
      {
        title: "Nodejs快速入门",
        click: 100,
        price: 3200
      },
      {
        title: "html+css",
        click: 110,
        price: 1200
      },
      {
        title: "js入门到精通",
        click: 2100,
        price: 2000
      }
    ];

    // lessons.sort((a, b) => b.click - a.click)

    /* lessons.sort(function (a, b) {
      return b.click - a.click
    }) */

    // 箭头函数的写法
    const myOrder = fieldName => (a, b) => b[fieldName] - a[fieldName];
    lessons.sort(myOrder('click'))


    // 保存
function myOrder(fieldName) {
      return function (a, b) {
        return b[fieldName] - a[fieldName]
      }
    } 

2.3.1列表元素绑定事件
for (var i = 0; i < liList.length; i++) {
	liList[i].onclick = (function (i) {
		return function () {
			console.log(`当前点击按钮的索引:${i}`)
		}
	})(i)
}
2.3.2闭包实现模块化保护
var myModule = (function () {
	var name = '张三'
	function getName() { return name }
	return {
		getName
	}
})()

//例子
const {getPhone,setPhone} = (function () {
      var phone = '1232131223'
      function getPhone() {
        return '我的电话号码:' + phone
      }
      function setPhone(phoneNum){
        phone = phoneNum
      }
      // 暴露到外部调用的方法
      return {
        getPhone,
        setPhone
      }
    })()
    
    console.log(getPhone())
	setPhone('22222222222')
	console.log(getPhone())
2.3.3惰性调用
  function getStyle(...args) {
      // ie有的
      // if (document.body.currentStyle) { // ie浏览器中有
      if (!('getComputedStyle' in window)) { // ie浏览器中有
        getStyle = function (...args) {
          return args[0].currentStyle[args[1]]
        }
      } else {
        getStyle = function (...args) {
          return window.getComputedStyle(args[0])[args[1]]
        }
      }
      return getStyle(...args)
    }
    console.log(getStyle(document.getElementById('box'), 'width'))
    console.log(getStyle(document.getElementById('box'), 'width'))
2.3.4函数柯里化

柯里化是一个预处理思想,使用闭包形成一个不被释放的上下文,把一些信息存储起来,以后基于作用域链,访问到事先存储的信息,然后进行相关的处理,我们把这种模式称为柯里化函数。

//例子
function curring(n = 0) {
      return function (...args) {
        return args.reduce((prev, curr) => prev + curr, n)
      }
    }
    const sum = curring()
     console.log(sum(1, 2, 3))

3.this指向问题

3.1this指向主要分为5类,分别是:
  1. 事件绑定中的this
  2. 普通函数执行中的this
  3. 箭头函数执行中的this
  4. 构造函数中的this
  5. 基于call/apply/bind强制改变中的this

3.2事件绑定中的this

IE6~8中基于attachEvent实现事件绑定,事件触发方法执行,方法中的this不在是元素本身,一般情况都是指向window


 // 绑定事件
    /* document.getElementById('btn').addEventListener('click', function () {
      // this ==> 当前点击的dom对象
      console.log(this)
    }) */


    // ie和w3c一样的 this ==> 当前点击的dom对象
    /* document.getElementById('btn').onclick = function () {
      // this ==> 当前点击的dom对象
      // console.log(this.tagName)
      console.log(this)
    } */
    // ie绑定
    document.getElementById('btn').attachEvent('onclick', function () {
      // this指向到window
      console.log(this === window)
    })

3.3普通函数执行的this

1.函数执行,看函数前面是否有“点”,有“点”,“点”前面是谁this就是谁,没有点“点”this是window,(js严格模式下是undefined)
2.自执行函数执行,其内的this一般都是window,严格模式下为undefined
3.回调函数和闭包中的this为window或undefined,除非做过特殊处理(如:数组中的forEach)

 // 调用普通函数,如果前面有.,则.前的对象就是this的指向
    // this => obj
    // obj.fn()
    // this => obj.fn2
    // obj.fn2.fn3()
    // 闭包中的this,一般都是指向window
    //obj.fn4()()
    /* var fn = obj.fn4()
    window.fn() */

    // 回调函数中的this一般指向window
    /* [1, 2, 3].forEach(function (item,index) {
      console.log(this)
    }); */
    /* [1, 2, 3].forEach(function (item, index) {
      // this => {id:1}
      console.log(this)
    }, { id: 1 }); */


    // 自执行函数中的this指向到window
    (function(){
      console.log(this)
    })()

3.4箭头函数中的this

箭头函数中没有自己的this,所用到的this都是所处上下文中的this

  <button id="btn">点击事件</button>


  <script>
    // 箭头函数,定义在window中,this指向到window
    /* const fn = () => console.log(this)
    fn() */

    // 箭头可以保留this的指向,因为它本身没有,它只听你所在的作用域
    btn.onclick = function () {
      /* function fn() {
        console.log(this)
      } */
      const fn = () => console.log(this)
      fn()
    }

    var obj = {
      // window
      fn:()=>console.log(this)
    }

    var obj = {
      fn: function () {
        /* function fn2() {
          console.log(this)
        } */
        const fn2 = () => {
          const fn3 = () => {
            console.log(this)
          }
          fn3()
        }
        fn2()
      }
    }
    obj.fn()

3.5 call/apply/bind强制改变this指向

3.5.1 call方法

给参数1对象中添加一个属性,并把fn函数赋值给它(fn.call({},参数)),
把参数1对象中新添加的属性方法,并把参数赋值过去
删除刚新添加的属性方法

call和apply都是自执行,调用即执行,call的性能略好于apply,因为call不用分析参数,直接用

call的实现思路:
先给参数1添加一个属性并且让这个属性值赋值为 fn,执行自定义属性方法,删除刚刚添加的自定义属性

function fn(a, b) {
      console.log(this, a, b)
    }

    var obj = {
      id: 1000
    }
    // call执行的函数,如果有参数,则以,逗号方式一个个去添加
    // fn.call(obj, 1, 2)
    fn.call(obj, ...[1, 2])

    // apply 参数函数有参数,则以数组的方式来传递
    // fn.apply(obj, [10, 20])
3.5.2apply
function fn(a, b) {
      console.log(this, a, b)
    }

    var obj = {
      id: 1000
    }
    // call执行的函数,如果有参数,则以,逗号方式一个个去添加
    // fn.call(obj, 1, 2)
    fn.call(obj, ...[1, 2])

    // apply 参数函数有参数,则以数组的方式来传递
    // fn.apply(obj, [10, 20])

//=====================
//注意
// 在非严格模式下,如果传入的是一个null/undefined/参数1为空,都指this指向到window
    // ***** 如果参数1为空,在非严格模式下面指向为window,在严格模式下,指向为undefined ****
    // fn.call()
    // 在严格模式下写谁就指向谁 null
    // fn.call(null)
    // 指向undefined
    // fn.call(undefined)
3.5.3 bind
    // bind,它调用的方法不会立即执行,只会给预先处理好,放在此处等待被调用
    // bind绑定的函数有参数,则和call中的参数传递一样的

    var obj = {
      id: 1,
      name: '张三'
    }

    function fn(a, b) {
      console.log(this, a, b)
    }

    // console.log(fn.bind(obj)) 
    // react中大量使用
    document.querySelector('#box').onclick = fn.bind(obj,1,2)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值