事件 + 表单

事件

补充表格代码:

<!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>Document</title>
    <style>
        table {
            width: 600px;
            border: 1px solid #000;
            text-align: center;
            border-collapse: collapse;
            border-spacing: 0px;
        }
        tr,
        th,
        td {
            border: 1px solid #000;
        }
        tbody input {
            width: 90%;
            border: none;
            outline: none;
        }
    </style>
</head>
<body>
    <div>
        <p>
            序列号 <input id="sId">
        </p>
        <p>
            姓 名 <input id="sName">
        </p>
        <p>
            电 话 <input id="sTel">
        </p>
        <p>
            <button id="save">保存</button>
        </p>
    </div>
    <input id="txt"> <button id="search">搜索</button>
    <table>
        <thead>
            <tr>
                <th>id</th>
                <th>姓名</th>
                <th>电话</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody id="tab">

        </tbody>
    </table>

</body>
</html>
<script>
    var oId = document.getElementById("sId");//id
    var oName = document.getElementById("sName");//姓名
    var oTel = document.getElementById("sTel"); //电话
    var oTxt = document.getElementById("txt"); //输入内容
    var oSearch = document.getElementById("search");//搜索按钮
    var oSave = document.getElementById("save");//保存按钮
    var oTab = document.getElementById("tab"); //表格
    //1. 模拟一些数据
    var data = [{
        id: 1,
        name: "刘德华",
        tel: 13812345678
    },
    {
        id: 2,
        name: "周星驰",
        tel: 13812345678
    }]

    //0.页面加载显示 模拟数据到页面
    loadData(data);
    //2.点击保存按钮,输入框的数据,做成一个对象,把该对象添加到模拟数据里
    oSave.onclick = function () {
        var obj = {
            id: oId.value,
            name: oName.value,
            tel: oTel.value,
        }
        //在保存的时候,拿 obj里的id与 模拟数据里的id继续比较
        //id与电话号码不能重复
        var isReg = data.some(function (item) {
            return item.id == obj.id || item.tel == obj.tel;
        })
        //如果isReg 为true,说明已经存在
        if (isReg) {
            return;
        }
        data.push(obj);
        //再一次调用显示数据
        loadData(data);
    }
    function loadData(arr) {
        //判断 arr 必须是数组
        if (!Array.isArray(arr)) {
            return;
        }
        var strHtml = "";
        arr.forEach(function (item) {
            strHtml += `
                    <tr>
                        <td>${item.id}</td>
                        <td>${item.name}</td>
                        <td>${item.tel}</td>
                        <td>
                            <a href='javascript:void(0)' onclick=del(this,${item.id})>删除</a>
                            <a href='javascript:void(0)' onclick=edit(this,${item.id})>编辑</a>
                            <a style='display:none' href='javascript:void(0)' onclick=save(this,${item.id})>保存</a>
                        </td>
                    </tr>                `
        });
        oTab.innerHTML = strHtml;
    }
    //定义了一个删除函数
    function del(o, id) {
        //1.先 根据id先出模拟数据里的 对应数据
        var findIndex = -1;
        data.forEach(function (item, index) {
            if (item.id == id) {
                findIndex = index;
            }
        })
        //根据下标删除
        data.splice(findIndex, 1);
        //2.页面上的 tr标签 也要被删除
        o.parentNode.parentNode.remove();
    }
    //搜索功能
    oSearch.onclick = function () {
        //1.获取到输入框的内容
        var strName = oTxt.value;
        //2.拿strName 与模拟的数据,进行过滤
        var newData = data.filter(function (item) {
            return item.name.indexOf(strName) != -1
        })
        //加载显示的数据,inneerHTML会把之前的数据覆盖掉
        loadData(newData)
    }
    //编辑  o是a标签
    function edit(o, id) {
        o.style.display = "none";
        (o.nextElementSibling || o.nextSibling).style.display = "inline-block";
        // 拿到用户名的td里头 插入一个input
        //先取值 刘德华
        var strName = o.parentNode.parentNode.children[1].innerText;
        //把刘德华放入到一个 输入框里,在把输入框插入到 第2个td里
        o.parentNode.parentNode.children[1].innerHTML = `<input value=${strName}>`;
        //先取出电话号码
        var strTel = o.parentNode.parentNode.children[2].innerText;
        o.parentNode.parentNode.children[2].innerHTML = `<input value=${strTel}>`;
    }
    //保存 o是a标签
    function save(o, id) {
        o.style.display = "none"; //保存 隐藏
        // 编辑显示
        (o.previousElementSibling || o.previousSibling).style.display = "inline-block"
        // 1.根据id找到下标,在于对应下标的地方,把输入的值,覆盖模拟数据里某对象的数据
        var findIndex = -1;
        data.forEach(function (item, index) {
            if (item.id == id) {
                findIndex = index;
            }
        })
        data[findIndex].name = o.parentNode.parentNode.children[1].children[0].value;
        data[findIndex].tel = o.parentNode.parentNode.children[2].children[0].value;
        //把输入的内容,利用innerHTML 覆盖原来的 input框
        o.parentNode.parentNode.children[1].innerHTML = data[findIndex].name
        o.parentNode.parentNode.children[2].innerHTML = data[findIndex].tel;
    }
</script>

事件

日常生活中事件: 发生并得到处理的操作
在JS中的事件是: 用户在页面上操作, 然后我们要调用函数来处理.
事件触发:用户在页面上操作(如点击按钮, 鼠标滑过, 鼠标点击, 鼠标松开, 文本框获得焦点, 失去焦点等), 就是事件触发.

事件的模式

JavaScript有两种事件实现模式: 内联模式, 脚本模式.
内联模式 :
直接在HTML标签中添加事件. 这种模型是最传统简单的一种处理事件的方法。但是这种模式中事件和HTML是混写的, 并没有将JS与HTML分离, 当代码量多了以后,对后期代码维护和扩展很不利.

<input type="button" value="按钮" onclick="alert('hello');" /> 
注意: 单双引号
//执行自定义的JS函数 
<input type="button"value="按钮" onclick="btnClick();" /> 
注意: 内联模式调用的函数不能放到window.onload里面, 否则会找不到该函数.

脚本模式

脚本模式能将JS代码和HTML代码分离, 符合代码规范.
使用脚本模式我们需要先获取到元素节点对象, 再针对该节点对象添加事件.

var box = document.getElementById('box'); 
添加事件方式一 :  通过匿名函数,可以直接触发对应的代码 (推荐)
box.onclick = function() {  //给box节点对象添加点击事件onclick
         console.log('Hello world!'); 
};
添加事件方式二 :  通过指定的函数名赋值的方式 来执行函数
box.onclick = func;    //注意这里不能写成func()
function func() {        //给box节点对象添加点击事件onclick
         console.log('Hello world!'); 
};

事件处理由三个部分组成:1, 触发事件的元素节点对象;2, 事件处理函数;3, 事件执行函数

例如:单击文档任意处。 
document.onclick = function(){ 
        console.log('单击了文档页面的某一个地方'); 
};

在上面的程序中:
document : 是触发事件的对象, 表示触发事件的元素所在区域;
onclick : 表示一个事件处理函数(on+事件类型click)
function(){} : 匿名函数是被执行的函数, 用于触发事件后执行;
所有的事件处理函数都会都有两个部分组成,on+事件类型;
例如 : onclick事件处理函数就是由on加上click;
注意: 事件处理函数一般都是小写字母

事件的分类

JavaScript 可以处理的事件种类有三种:鼠标事件, 键盘事件和 HTML事件.
鼠标事件,页面所有元素都可触发鼠标事件;

click: 当单击鼠标按钮并在松开时触发
onclick = function() {
        console.log('单击了鼠标'); 
};
dblclick: 当双击鼠标按钮时触发。
ondblclick = function() {
        console.log('双击了鼠标'); 
};
mousedown:当按下了鼠标还未松开时触发。 
onmousedown = function() {
        console.log('按下鼠标'); 
};
mouseup: 释放鼠标按钮时触发。 
onmouseup = function() {
        console.log('松开了鼠标'); 
};
mouseover:当鼠标移入某个元素的那一刻触发。
onmouseover = function() {
        console.log('鼠标移入了'); 
}; 
mouseout:当鼠标刚移出某个元素的那一刻触发。 
onmouseout = function() {
        console.log('鼠标移出了'); 
}; 
mousemove:当鼠标指针在某个元素上移动时触发。
onmousemove = function() {
        console.log('鼠标移动了'); 
};
mouseenter:当鼠标移入某个元素的那一刻触发。
onmouseenter = function() {
        console.log('鼠标移入了'); 
}; 
mouseleave:当鼠标刚移出某个元素的那一刻触发。 
onmouseleave = function() {
        console.log('鼠标移出了'); 
};

(onmouseover与onmouseout) 比(onmouseenter和onmouseleave) 早执行
(onmouseover与onmouseout)遇到子元素 也会触发,
(onmouseenter和onmouseleave) 遇到子元素 '不'会触发
鼠标的滚轮事件

 oBox.onmousewheel = function () {
            console.log(1111);
        }

键盘事件,在键盘上按下键时触发的事件; (一般由window对象或者document对象调用)

keydown:当用户按下键盘上某个键触发,如果按住不放,会重复触发。
window.onkeydown = function() {
        console.log(按下了键盘上的某个键); 
};

keypress:当用户按下键盘上的字符键触发,如果按住不放,会重复触发
window.onkeypress = function() { 
        console.log('按下了键盘上的字符键'); 
};

keyup:当用户释放键盘上的某个键触发。
window.onkeyup = function() {
        console.log(松开键盘上的某个键); 
};

HTML事件,跟HTML页面相关的事件;

load:当页面完全加载后触发
window.onload = function() { 
        console.log('页面已经加载完毕'); 
};
unload:当页面完全卸载后触发
window.onunload = function() { 
        console.log('页面已经卸载完毕'); 
};
select:当用户选择文本框(input 或 textarea)中的内容触发。 
input.onselect = function() { 
        console.log('选择了文本框中的内容'); 
};
change:当文本框(input 或 textarea)内容改变且失去焦点后触发。 
input.onchange = function() { 
        console.log('文本框中内容改变了'); 
};
 //页面结构加载完成,就触发
window.addEventListener("DOMContentLoaded", function () {
console.log("over");
卸载
window.onunload = function () {
console.log("卸载.......");
改变窗口事件
window.onresize = function () {
console.log("onresize");
滚轮  onwheel  onmousewheel
var oBox=document.querySelector(".box");
oBox.onwheel=function(){
      console.log("onwheel");
}
focus:当页面或者元素获得焦点时触发。 
input.onfocus = function() { 
        console.log('文本框获得焦点'); 
};
blur:当页面或元素失去焦点时触发。
input.onblur = function() { 
        console.log('文本框失去焦点'); 
};
submit:当用户点击提交按钮在<form>元素节点上触发。
form.onsubmit = function() { 
        console.log(‘提交form表单’);  
};
reset:当用户点击重置按钮在<form>元素节点上触发。 
form.onreset = function() { 
        console.log('重置form表单'); 
};
scroll:当用户滚动带滚动条的元素时触发。
window.onscroll= function() { 
        console.log('滚动了滚动条了'); 
};

submit 重点

<form>
        <p>
            <input name="uname" placeholder="用户名">
        </p>
        <p>
            <!--  button在表单里,默认是submit类型 -->
            <!-- <button>提交</button> -->
            <input type="submit" value="提交">
            <button type="reset">重置</button>
        </p>
    </form>
    <script>
        // 只有submit才会触发 form表单的默认提交行为
        //提交的时候,必须要先经过js的控制,如果js同意提交,才触发默认行为
        //重点
        document.forms[0].onsubmit = function () {
            console.log(11111);
            // return false; 阻止onsubmit默认的提交行为
            return false;// js 说 不让提交
            // return true;
        }
        //了解 重置输入的内容
        document.forms[0].onreset = function () {
            console.log(111);
            // return true;
        }
    </script>

事件对象

在事件触发时的一条记录信息,就是事件对象
该对象里有哪些信息?

  1. 位置,事件的类型,目标元素,到元素,屏幕等等的距离
    事件对象的属性:button 0 左键 ,1 滚轮键 ,2 右键
    target 目标 点了谁? srcElement ie
var oBox = document.querySelector(".box");
        oBox.onmousedown = function (evt) {
            //在ie下 window.event
            //在google,使用形参true
            //事件对象的兼容写法
            //  google      ie
            var e = evt || window.event;
            // console.log(e.button);
            // console.log(e.srcElement);
            // this不等于 target
            // this 就是万年不变的 box
            // target 鼠标点了谁,就是谁  (事件委托就要借助它)
            var ele = e.target || e.srcElement;
            console.log(ele);
            console.log(this);
浏览器渲染页面的原理及流程

1.根据html文件构建DOM树和CSSOM树。构建DOM树期间,如果遇到JS,阻塞DOM树及CSSOM树的构建,优先加载JS文件,加载完毕,再继续构建DOM树及CSSOM树。
2.构建渲染树(Render Tree)。
3.页面的重绘(repaint)与重排(reflow,也有称回流)。页面渲染完成后,若JS操作了DOM节点,根据JS对DOM操作动作的大小,浏览器对页面进行重绘或是回流


image.png

重绘和回流(repaint&reflow)

当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流

导致回流的操作:
1、页面首次渲染
2、浏览器窗口大小发生改变
3、元素尺寸或位置发生改变
4、元素内容变化(文字数量或图片大小改变而引起的计算值宽度和高度改变)
5、元素字体大小变化
6、添加或者删除可见的DOM元素
7、激活CSS伪类(例如::hover)
8、查询某些属性或调用某些方法
9、offsetWidth,width,clientWidth,scrollTop/scrollHeight的计算,会使浏览器将渐进回流队列Flush,立即执行回流。

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘
回流必定会发生重绘,重绘不一定会引发回流。

如何避免重绘和回流?

css:

1.避免使用table布局,可能很小的一个小改动会造成整个table的重新布局
2.尽可能在DOM树的最末端改变class。
3.避免设置多层内联样式。
4.将动画效果应用到position属性为absolute或fixed的元素上。
5.动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用requestAnimationFrame
6.避免使用CSS表达式(例如:calc())
7.使用transform替代top
8.使用visibility替换display: none,因为前者只会引起重绘,后者会引发回流(改变了布局)
将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点

js:

1.避免频繁操作样式,最好一次性重写style属性,cssText,或者将样式列表定义为class并一次性更改class属性。
2.避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
3.也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
4.避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
5.对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容