DOM

dom工作原理:
1.代码从硬盘 读取到内存(代码)
2.生成dom树
*修改了dom树,最终渲染的页面也会改变
3.渲染引擎开始渲染dom树(页面)

查询页面元素

1.获取单个元素 : document.querySelector('选择器')

  * @description: 获取满足条件的第一个元素
  * @param {string}  选择器字符串 
  * @return:  dom对象 | null
 

2.获取多个元素 : document.querySelectorAll('选择器')

  * @description: 获取满足条件 所有元素
  * @param {string}  选择器字符串  
  * @return:  一定是伪数组 (有三要素下标、元素、长度。 但是没有数组方法 )


元素的内容操作
(1)元素.innerText; 只能操作文本,不能解析html标签.
(2)元素.innerHTML;可以解析html标签

元素的属性操作
(1)1.获取属性 元素.属性名
(2)2.设置属性 元素.属性名 = 值

dom事件分为两类
鼠标事件:
(1)鼠标单击事件:onclick
(2)鼠标双击事件:ondblclick
(3)鼠标移入事件:onmouseenter
(4)鼠标移出事件:onmouseleave
(5)鼠标移动事件:onmousemove

键盘事件:
(1)onfocus:键盘成为焦点
(2)onblur:键盘失去焦点
(3)oninput:键盘输入(实时获取输入框内容:字数统计+模糊查询)
(4)onkeydown:键盘按下(监听enter键)
(5)onkeyup:键盘松开

input.addEventListener('keydown', function (e) {

  console.log('键盘按下');
  e.key == 'Enter'
})


元素className和classLIst操作样式

    (1)修改单个样式:   
    (2)修改多个样式:   
    (3)修改多个样式:   
  
    //通过className操作类名:元素.className='类名'
    //先获取元素
    let box = document.querySelector('.box')


    //1.获取类名 : 
    //由于class是js中的关键字,所以要用className
    console.log(box.className)

    //2.设置类名  : 
    //box.className='类名' className会覆盖以前的类名
    // box.className = 'one'


    //通过classList操作类名
    // 新增类名 
    // 元素.classList.add('类名')
    box.classList.add('two')

    //删除类名
    // 元素.classList.remove('类名')
    box.classList.remove('one')

    //切换类名 有则移除,无则新曾
    // 元素.classList.toggle('类名')
    box.classList.toggle('two')

    //判断类名
    // 元素.classList.contains('类名')
    // true:有类名  false:没有
    box.classList.contains('two')

事件及注册事件

/*

   1.交互功能 :   什么元素  在什么时刻  做什么事情
   2.事件三要素 
      事件源 : 什么元素
      事件类型 : 什么时刻
      事件处理函数 : 做什么事
   3.注册事件 : 给元素添加交互
      事件源.事件类型 = 事件处理函数
   4.事件原理及注意点
    (1)事件处理函数在注册的时候不会执行. (函数在声明的时候不会执行)
    (2)事件处理函数只有两种情况可以执行
      第一种: 用户主动触发交互, 浏览器会捕捉交互,底层会自动帮我们调用对象的方法
      第二种: 手动调用对象事件处理函数
   */
let box = document.querySelector('.box')
box.addEventListener('click', function () {
  box.style.backgroundColor = 'blue'
})

排他思想

  1.排他思想场景 : 多个元素,只能选中一个
  2.排他思想流程 :两种思路 
  循环排他(万能的) :(1)循环干掉所有兄弟 (2)复活自己
  类名排他(一定要有类名):(1)使用类名选择器干掉选中的兄弟 (2)复活自己
  
  总结:元素有类名就用类名排他,没有类就用循环排他 .切记两者不可混用
  类名排他:通过classList类名修改样式
  循环排他 通过style修改样式

1.事件源 : 输入框

    2.事件类型:
        onfouces: 成为焦点。  点击输入框出现光标的时候(此时用户可以输入文字)
        onblur: 失去焦点。    点击空白区域输入框光标消失的时候(此时用户不可以输入文字)

开关思想

2.开关思想 : 判断数组中是否所有元素都满足条件

        (1)声明开关变量 : 默认都满足
        (2)检测开关变量 : 遍历数组,找不满足
        (3)获取开关变量
    开关思想应用场景举例:
        (1)检测购物车是否所有商品都选中
        (2)检测注册是否每一个表单都填写数据
       

    //需求1: 判断数组中是否所有元素都大于0
    //都大于0 : 打印true   不是都大于0: false
    let arr1 = [20,66,0,80,90,100]

    //(1)声明开关变量
    let flag = true
    //(2)检测开关变量的值是否正确
    for(let i = 0;i<arr1.length;i++){
        if( arr1[i] <= 0 ){
            flag = false
            break
        }
    }
    //(3)开关结果
    console.log( flag )

attribute语法学习

自定义属性 : html本身没有的属性

      属性作用 : 存储数据

  1.获取自定义属性 :  元素.getAttribute('属性名')
  2.设置自定义属性 :  元素.setAttribute('属性名',属性值)
  3.移除自定义属性 :  元素.removeAttribute('属性名')
  

let box = document.querySelector('#box')

  //1.获取自定义属性(有返回值)
  console.log( box.getAttribute('aaa') )
  //2.设置 自定义属性
  box.setAttribute('aaa','1111')//覆盖
  box.setAttribute('bbb','2222')//新增
  //3. 移除 自定义属性
  box.removeAttribute('bbb','2222')

DOM节点

节点增删改查
    1.查节点 : 
        查子元素:  元素.children
        查兄弟元素:  
            上一个元素: 元素.previousElementSibling
            下一个元素: 元素.nextElementSibling
        查父元素 : 元素.parentNode
    2.增 : document.createElement()
        (1)内存创建空节点:   document.createElement('标签名')
        (2)设置标签内容
        (3)添加到页面dom
            新增到最后面   :  父元素.appendChild(元素)
            新增到元素前面 :  父元素.insertBefore(要加的元素,哪一个元素前面)

[ document.write('') 开发中几乎不用
元素.innerHTML = '' 新增100以内的元素的时候可以用

          覆盖操作:  元素.innerHTML = '<h1>标题</h1>'
          新增操作:  元素.innerHTML += '<h1>标题</h1>']


    3.删 : 父元素.removeChild(子元素)

克隆节点 : 复制节点

    元素.cloneNode(true)
        默认false : 浅克隆,只克隆元素自身 
        true : 深克隆,克隆元素自身  + 所有后代元素

    

定时器:

  1.定时器作用 : 一段代码 间隔时间 重复执行

回调函数:如果一个函数的参数也是函数,那么这个函数就叫做回调函数

  2.定时器语法 :
 * @description:开启定时器
 * @param {function}
  *回调函数:如果一个函数的参数也是函数,那么这个函数就叫做回调函数
 * @param {number}间隔时间 单位 毫秒 1s=1000
 * @return: 定时器ID
 * 一个浏览器可以开启很多个不同的定时器,浏览器伪类便于管理,会给每一个定时器一个编号,我们称之为ID 


   2.1.永久定时器:一旦开启,自动永久执行,只能手动清除
    (1)开启定时器 setInterval(function(){},间隔时间)
    (2)清除定时器:clearInterval(timeID)
    2.2 一次定时器:间隔时间只会执行一次,执行完毕后会自动清除
     (1)开启定时器:let  timeID=setTimeout(function(){},间隔时间)   间隔时间为毫秒数
     (2)清除定时器:clearInterval(timeID)
  

事件监听:

1.点语法注册事件: 事件源.事件类型 = 事件处理函数

        * 特点:不能注册‘同名事件’, 否则会覆盖

2.事件源.addEventListener('事件类型',事件处理函数)

        * 特点:可以注册‘同名事件’,依次触发

移除事件监听:
1.事件源.事件类型=null(传统)
2.事件源.removeEventListener('事件类型',事件处理函数)

阻止默认事件:
html中有部分标签自带点击事件 : form表单,a标签

    2.如果给这些标签注册点击事件,会默认跳转
    3. 阻止默认事件 : 执行自己注册的事件
        e.preventDefault()

表单清空(重置表单):form对象.reser()

事件冒泡与捕获

  1.事件冒泡 : 当触发子元素的事件时候,所有的父级元素‘同名事件’会被依次触发
     1.1 规则:  子元素->父元素->body->html->document->window
     1.2 应用场景:  事件委托技术 

事件委托:

事件委托 : 给父元素注册事件,委托给子元素处理

  2.1事件委托底层原理 :事件冒泡
  2.2事件委托应用:给动态新增li元素注册事件
  2.3事件委托注意点:
   不能使用this:this代表事件源,指向父元素
   需要使用e.target:事件目标(触发本次冒泡的子元素)



  2.事件捕获 : 当触发子元素的事件时候,先从最顶级父元素,一级一级往里触发
    1.1 规则:  window->document->html->body->父元素->子元素

  3.默认情况下,所有的注册事件都是冒泡事件。 只有唯一一种方式可以注册捕获事件:
    元素.addEventListener('事件类型',事件处理函数,true)
  
  4.事件流三个阶段:  e.eventPhase
    1-捕获阶段
    2-目标阶段
    3-冒泡阶段

  5.阻止事件流动 :  e.stopPropagation()
  写在哪个事件处理函数中,就从哪里开始阻止

三大家族

  1. offset家族 : 获取元素 ‘自身’ 的真实宽高 和 真实位置
    offsetWidth / offsetHeight : 获取 width+padding+border
    offsetLeft / offsetTop : 获取 左/上 外边框 到定位父元素 左/上 内边框距离
  1. scroll家族 : 获取元素 ‘内容’ 的真实宽高 和 位置
    scrollWidth / scrollHeight : 获取内容的宽高
    scrollLeft / scrollTop : 内容的位置(就是滚动条滚动的距离)
    获取网页滚动距离

         1.给页面注册滚动事件 :  window.onscroll
         2.获取页面滚动距离 : document.documentElement.scrollTop
    

3.client家族 : 获取元素 ‘可视区域’ 宽高 和 位置

  clientWidth / clientHeight : 可视区域大小
  clientLeft / clientTop : 可视区域位置(就是左边框 和 上边框 宽度)



   (1)js中几乎所有的内置对象,都是通过new来创建的
        new Date()
        new RegExp()
        new Array()
        new Object()
    (2)js中有三种内置对象有简写语法
        数组:  []
        对象:  {}
        正则:  /正则/

npm上传

连接npm
命令:

npm adduser

这个命令需要输入四个信息以供连接上npmjs:

● 用户名
● 密码
● 邮箱(是你在npmjs官网上注册时使用的信息)
● 校验密码。它会向你的邮箱发邮件

如果你已经不是第一次连接了,这一步是可以省略的

你也可以通过如下命令检查自己是否连接成功了。

npm who am i
npm logout

把包上传到npm

命令: npm publish

如果成功:

-----------------------------------
npm notice
npm notice package: tool61@1.0.0
npm notice === Tarball Contents ===
npm notice 1.3kB index.js
npm notice 220B  package.json
npm notice === Tarball Details ===
npm notice name:          tool61
npm notice version:       1.0.0
npm notice package size:  855 B
npm notice unpacked size: 1.5 kB
npm notice shasum:        3bfba7bc92e242810a850ac39ded7ebe992a6d9c
npm notice integrity:     sha512-VoRuxxbcGzXen[...]v3tKWYUT1B1AQ==
npm notice total files:   2
npm notice
+ tool61@1.0.0

出错的可能是:
● 这个包名被别人先用了。
● 包的版本号不对:每次publish时,包的版本号都应该要大于之前的版本号。
文件过大。你可能需要创建.npmignore文件来设置在打包时要忽略哪些文件。如下是一个demo.

# .npmignore
/node_modules
npm-debug.log
/src
/examples
/build

如果没有报错,则表示一切ok,你可以用你的帐号密码登陆npm,去查看你名下的package是否有了myNpm
下载使用
通过npm install 包名即可来安装包。 然后,告诉你的小伙伴们去下载使用吧。
删除包

npm unpublish --force //强制删除

如果你的包没有什么用处,建议删除掉,以节约公共资源。
更新包

  1. 修改代码,保存。
  2. 更新版本号。可直接在package.json中修改:只能改大,不能改小。
  3. 重新publish

发表评论