博客

  • 针对transform中的几种值的先后顺序

    HTML代码:

    <div class="wrapper">
    	<div></div>
    	<div class="div1">div1</div>
    	<div class="div2">div2</div>
    	<div class="div3">div3</div>
    </div>

    translate和scale

    CSS代码:

    div {
    	width: 100px;
    	height: 100px;
    	background: tomato;
    }
    .wrapper {
    	width: 500px;
    	height: 400px;
    	border: 1px solid #000;
    	margin: 20px auto 0;
    	background: none;
    }
    .div1 {
    	transform: translateX(400px);
      background: lightblue;
    }
    .div2 {
    	transform: translateX(400px) scale(0.5);
      background: pink;
    }
    .div3 {
    	transform: scale(0.5) translateX(400px);
      background: lightcoral;
    }

    translateX(400px)

    translateX(400px) scale(0.5)

    scale(0.5) translateX(400px)

    将光标放在该区域内即可播放(移动端点击该区域)

    (代码作了适配处理,以实际效果为准)

    如上,默认的位移和形变的基点是中心,所以我们按照盒子的中心来做位移的衡量基点。第一个盒子为初始位置,第二个第三个都到了我们想要的位置(位移为400px),但是第四个盒子就出现了问题,位移为200px。

    按照常理,不管scale和translate的顺序如何,都应该达到我们期望的位置,但是如今我们发现如果先位移,后缩放,则可以达到我们期望的位置,但是当顺序反过来,即先缩放,后位移的话,则会将位移的步长同时缩小相应的倍数(这里我们缩放到1/2,所以相应的位移从原来的400px缩放到200px)。

    translate和rotate

    div{
        width:100px;
        height: 100px;
        background: tomato;
        transition: 1s all ease;
    }
    .wrapper{
        width:500px;
        height: 600px;
        border:1px solid #000;
        margin:20px auto 0;
        background: none;
    }
    .div1{
        transform: translateX(200px);
        background: lightblue;
    }
    .div2{
        transform: translateX(200px) rotate(45deg);
        background: pink;
    }
    .div3{
        transform: rotate(45deg) translateX(200px);
        background: lightcoral;
        }
    

    transform: translateX(200px)

    transform: translateX(200px) rotate(45deg)

    transform: rotate(45deg) translateX(200px)

    将光标放在该区域内即可播放(移动端点击该区域)

    (代码作了适配处理,以实际效果为准)

    如图,第二个第三个盒子同样达到了我们的预期,都向右移动了200px;但是第四个盒子又出现了问题,我们给的水平位移,但是在竖直方向也有了位移,不仅如此,向右移动的距离也没有200px.

    其实,当我们先旋转的时候,对于盒子的坐标系也旋转了.

    总结

    当我们在旋转后再进行位移的时候,其实是按照旋转后的坐标系位移,在我们视觉中就产生了向右位移了一部分,向下移动了一部分。

    总而言之,在transform中,当我们同时有位移和其他属性的时候,记得要将位移放到最前,先位移到我们期望的位置,然后再进行其他的形变。

    版权声明:本文为CSDN博主「crazyJialin」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

    原文链接:https://blog.csdn.net/crazy_jialin/article/details/77969990

  • 事件委托

    • 优点:给父级元素加事件(可以提高性能)
    • 原理:事件委托其实是利用事件冒泡的特点,给父元素添加事件,子元素可以触发
    • 实现:事件对象.target 可以获得真正触发事件的元素

    小案例

       <div class="father">
    	<p class="son">第1个p标签</p>
                         ···
                         ···
    	<p class="son">第6个p标签</p>
       </div>
    
       <!-- js -->
       <script>
       let father = document.querySelector('.father')
    
       father.addEventListener('click', function (e) {
    
    	e.target.style.color = 'lightblue'
    
       })
       </script>
  • 事件流

    事件流指的是事件完整执行过程中的流动路径

    捕获阶段是从父到子 / 冒泡阶段是从子到父

    事件冒泡

    当一个元素的某一事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。

    简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件

    事件冒泡默认存在

    div --> ··· --> body --> html --> document

    <div class="father">
        <div class="son"></div>
    </div>
    
    <script>
        let fa = document.querySelector('.father')
        let son = document.querySelector('.son')
        //father
        fa.addEventListener('click', function () {
            alert('father')
        })
      	//son
        son.addEventListener('click', function () {
            alert('son')
        })
      	//grandfather
        document.addEventListener('click', function () {
            alert('grandfather')
        })
      
    //点击son  son --> father --> grandfather
    </script>
    

    事件捕获

    从DOM的根元素开始去执行对应的事件 (从外到里)

    document --> html --> body --> ··· --> div

    	btn.addEventListener('click' , function () {} , true)
    //btn.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
    
    • addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
    • 若传入false代表冒泡阶段触发,默认就是false
    • 若是用 L0 事件监听,则只有冒泡阶段,没有捕获

    阻止事件流动

    事件对象.stopPropagation()

    • 若想把事件就限制在当前元素内,就需要阻止事件流动
    • 阻止事件流动需要拿到事件对象
    • 此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效

    鼠标经过事件

    • mouseover 和 mouseout 会有冒泡效果
    • mouseenter 和 mouseleave 没有冒泡效果(推荐)

    阻止默认行为,比如链接点击不跳转,表单域的不提交

    事件对象.preventDefault()


    两种注册事件的区别

    传统on注册(L0)

    • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
    • 直接使用null覆盖偶就可以实现事件的解绑
    • 都是冒泡阶段执行的

    事件监听注册(L2)

    • 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
    • 后面注册的事件不会覆盖前面注册的事件(同一个事件)
    • 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
    • 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)
    • 匿名函数无法被解绑
  • 事件对象

    • 在事件绑定的回调函数的第一个参数就是事件对象
    • 一般命名为event、ev、e

    获取事件对象

    btn.addEventListener('click',funtcion(e){
      console.log(e)
    })
    

    常用属性

    type

    获取当前的事件类型

    clientX / clientY

    获取光标相对于浏览器可见窗口距离左上角的位置

    offsetX / offsetY

    获取光标相对于当前DOM元素距离左上角的位置

    pageX / pageY

    获取光标相对于文档距离左上角的位置

    key

    用户按下的键盘键的值

    target

    触发事件的对象(可用于事件委托)

    Event.target | MDN

    // Make a list
    var ul = document.createElement('ul');
    document.body.appendChild(ul);
    
    var li1 = document.createElement('li');
    var li2 = document.createElement('li');
    ul.appendChild(li1);
    ul.appendChild(li2);
    
    function hide(e){
      // e.target 引用着 <li> 元素
      // 不像 e.currentTarget 引用着其父级的 <ul> 元素.
      e.target.style.visibility = 'hidden';
    }
    
    // 添加监听事件到列表,当每个 <li> 被点击的时候都会触发。
    ul.addEventListener('click', hide, false);
    

    Event | MDN

  • DOM节点

    DOM树里每一个内容都称之为节点

    节点类型

    元素节点

    所有的标签

    比如bodydivhtml是根节点

    属性节点

    所有的属性 比如hrefsrc

    文本节点

    所有的文本

    其他

    查找节点

    父节点查找

    • parentNode 属性
    • 返回最近一级的父节点找不到返回为null
    子元素.parentNode //是属性 不需要加括号
    

    子节点查找

    children (重点)

    • 仅获得所有元素节点
    • 返回的还是一个伪数组
    父元素.children
    

    childNodes

    获得所有子节点、包括文本节点(空格、换行)、注释节点等

    兄弟关系查找

    下一个兄弟节点

    nextElementSibling属性

    上一个兄弟节点

    previousElementSibling属性

    增加节点

    创建节点

    创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点

    document.createElement('标签名')  //必须是字符串
    

    追加节点

    插入到父元素的最后一个子元素

    父元素.appendChild(要插入的元素)
    

    插入到父元素中某个子元素的前面

    父元素.insertBefore(要插入的元素,在哪个元素前面)
    

    克隆节点

    cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值

    元素.cloneNode(true or false)
    • 默认为false
    • 若为false,则代表克隆时不包含后代节点
    • 若为true,则代表克隆时会包含后代节点一起克隆

    注意:为了防止一个文档中出现两个ID重复的元素,使用cloneNode()方法克隆的节点在需要时应该指定另外一个与原ID值不同的ID

    删除节点

    JavaScript原生DOM操作中,要删除元素必须通过父元素删除

    Node.removeChild() 方法从DOM中删除一个子节点。返回删除的节点。

    let oldChild = node.removeChild(child)
    
    //OR
    
    element.removeChild(child)
    
    • child 是要移除的那个子节点
    • node 是child的父节点
    • oldChild保存对删除的子节点的引用. oldChild === child

    被移除的这个子节点仍然存在于内存中,只是没有添加到当前文档的DOM树中,因此,你还可以把这个节点重新添加回文档中,当然,实现要用另外一个变量比如上例中的oldChild来保存这个节点的引用. 如果使用上述语法中的第二种方法, 即没有使用 oldChild 来保存对这个节点的引用, 则认为被移除的节点已经是无用的, 在短时间内将会被内存管理回收.

    Node.removeChild | MDN

    如果上例中的child节点不是node节点的子节点,则该方法会抛出异常

  • 时间对象

    实例化

    在代码中出现了new关键字时,一般将这个操作称为实例化

    创建一个时间对象并获取时间

    //获得当前时间
    let date = new Date()
    
    //获得指定时间
    let date = new Date('1999-3-14')
    

    因为时间对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用的格式

    方法作用说明
    getFullYear()获得年份获取四位年份
    getMonth()获得月份取值为 0 ~ 11
    getDate()获取月份中的每一天不同月份取值也不相同
    getDay()获取星期取值为 0 ~ 6
    getHours()获取小时取值为 0 ~ 23
    getMinutes()获取分钟取值为 0 ~ 59
    getSeconds()获取秒取值为 0 ~ 59
    ·········

    时间戳

    指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式。

    //得到指定的时间戳 括号里是字符串!
    //1.
    +new Date('2022-3-1 18:00:00')
    
    //2.
    let date = new Date('2022-3-1 18:00:00')
    console.log(date.getTime())
    

    三种获取方式

    //1.简写(推荐)
    //直接获取
    +new Date()
    
    //2.
    //实例化
    let date = new Date()
    //获取时间戳
    date.getTime()
    
    //3.
    //无需实例化
    //只能获取当前的时间戳,前两种可以获取指定时间的时间戳
    Date.now()
    

    Date – JavaScript | MDN

  • 重排和重绘

    浏览器是如何进行界面渲染的

    回流 / 重排(reflow)

    当 Render Tree 中部分或者全部元素的尺寸结构布局等发生改变时,浏览器就会重新渲染部分全部文档的过程称为回流。

    会导致回流(重排)的操作:

    • 页面的首次刷新
    • 浏览器的窗口大小发生改变
    • 元素的大小或位置发生改变
    • 改变字体的大小
    • 内容的变化(如:input框的输入,图片的大小)
    • 激活css伪类 (如::hover)
    • 脚本操作DOM(添加或者删除可见的DOM元素)

    简单理解影响到布局了,就会有回流

    重绘(Repaints)

    由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如:colorbackground-coloroutline等), 称为重绘。

    重绘不一定引起回流,而回流一定会引起重绘。

    let s = document.body.style
    s.padding = '2px'              // 重排 + 重绘
    s.border = '1px solid red'    // 再次重排 + 重绘
    s.color = 'blue'             // 再次重绘
    s.backgroundColor = '#ccc'  // 再次重绘
    s.fontSize = '14px'        // 再次重排 + 重绘
  • 排他思想

    let btns = document.querySelectorAll('button')
    for (let i = 0; i < btns.length; i++) {
      
     //方法1
    btns[i].addEventListener('click', function () {
            // 干掉所有人 把所有按钮中的这个类都删除
            for (let j = 0; j < btns.length; j++) {
                btns[j].classList.remove('pink')
            }
            // 复活我自己 只给自己添加
            this.classList.add('pink')
        })
      
    //方法2
    btns[i].addEventListener('click', function () {
    		// 我只需要找出那个唯一的 pink类,删除
    		document.querySelector('.pink').classList.remove('pink')
    		// 我的
    		this.classList.add('pink')
        })
      
    }
  • 随机点名案例

    功能:

    • 点击开始按钮开始随机点名
    • 点击结束按钮抽取一个名字,并把抽到的名字删除
    • 直到抽到最后一个人,弹出重新开始按钮和“抽完了”提示文字

    HTML部分

    <div class="box">
    <h3>随机点名</h3>
    <p>幸运儿:<span class="luckyman"></span></p>
    <p class="alert">抽完啦</p>
    <div class="btn">
    <button class="start">开始</button>
    <button class="end" disabled>结束</button>
    <button class="reopen">重新开始</button>
    </div>
    </div>

    CSS部分

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      color: #333;
    }
    .box {
      user-select: none;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-around;
      margin: 3vw auto 0;
      height: 40vw;
      border-top: 0.6667vw solid #333;
      border-bottom: 0.6667vw solid #333;
    }
    .box h3 {
      font-size: 4vw;
    }
    .box p {
      font-size: 2.9333vw;
    }
    .box p span {
      display: inline-block;
      min-width: 6.6667vw;
      max-width: 20vw;
      border-bottom: 0.4vw solid #333;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    .btn button {
      width: 13.3333vw ;
      height: 5.3333vw;
      font-size: 2.4vw;
      border: 0.2667vw solid #333;
      margin: 0 1.3333vw;
      background: none;
      cursor: pointer;
    }
    button:disabled {
      color: #999;
      border: 0.2667vw solid #999;
      cursor: default;
    }
    .reopen {
      display: none;
    }
    .alert {
      display: none;
    }

    JS部分

    // 获取M-N之间的随机数
    let random = function (m, n) {
      let rNum = 0
      rNum = Math.floor(Math.random() * (m - n + 1) + n) //m - n + 1 向下取整,所以
      return rNum
    }
    // 随机名字函数
    let i = 0
    let nameArr = ["rose", "cool", "tony", "Liao", "Q"]
    let text = document.querySelector(".luckyman")
    let rName = function () {
      i = random(nameArr.length - 1, 0)
      let name = nameArr[i]
      text.innerHTML = name
    }
    //按钮事件绑定
    let start = document.querySelector(".start")
    let end = document.querySelector(".end")
    let reopen = document.querySelector(".reopen")
    let alert1 = document.querySelector(".alert")
    start.addEventListener("click", function () {
      //开启定时器
      t = setInterval(rName, 50)
      start.disabled = true
      end.disabled = false
      if (nameArr.length === 1) {
        start.disabled = true
        end.disabled = true
        alert1.style.display = "block"
        reopen.style.display = "inline-block"
        clearInterval(t)
      }
    })
    end.addEventListener("click", function () {
      //结束定时器
      clearInterval(t)
      start.disabled = false
      end.disabled = true
      //在数组删除被选中的名字
      nameArr.splice(i, 1)
    })
    //重新开始
    reopen.addEventListener("click", function () {
      nameArr = ["rose", "cool", "tony", "Liao", "Q"]
      start.disabled = false
      alert1.style.display = "none"
      text.innerHTML = ""
      reopen.style.display = ""
      
    })
  • 变量命名规则与规范

    1. 规则:

    • 不能用关键字
    • 关键字:有特殊含义的字符,JavaScript 内置的一些英语词汇。例如:letvariffor
    • 只能用下划线、字母、数字、$组成,且数字不能开头
    • 字母严格区分大小写,如 Age 和 age 是不同的变量

    2. 规范:

    • 起名要有意义
    • 遵守小驼峰命名法
    • 第一个单词首字母小写,后面每个单词首字母大写。例:userName