第九章:GUI事件

1.AWT事件模型概述
使用AWT或者Swing中的容器、组件和布局管理器就可以构建出图形界面,但是这时候该界面还并不能和用户进行交换,因为图形界面中的组件还没有添加事件监听器,所以还不能对用户在界面中的操作进行处理。

在Java事件模型中,必须存在事件对象、事件源、事件监听器三部分。事件对象是表示发生了什么事件,事件源表示是谁产生的这个事件对象,事件处理器接收到事件对象后,可以对这个事件进行处理。
事件模型中的三要素:事件对象、事件源、事件监听器
注:不光是GUI中,在java的其他地方也会使用到事件模型。

在Java中一个事件监听器就是指事件发生时被通知的对象。它有两个要求:首先,为了可以接收到特殊类型事件的通知,它必须在事件源中已经注册;其次,它必须实现接收和处理事件的方法。
例如:
//btn就是事件源
JButton btn = new JButton("测试");
//给事件源btn注册事件监听器
//这里使用了匿名内部类对象作为监听器
btn.addActionListener(new ActionListener() {
//监听器中实现接收和处理事件的方法
//ActionEvent类型的引用e指向的就是按钮上所产生的事件对象
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("hello");
}
});

XxxxListener 监听器接口
事件源.addXxxxListener(new XxxxListener(){
//实现接口中的抽象方法
});

在事件源上注册好监听器之后,只要是在该事件源上产生了特定的事件对象,事件监听器就会自动被触发,并执行相应的方法处理。
例如:在上面的例子基础上
当我们使用鼠标点击btn这个按钮之后,产生了一个鼠标点击的事件对象(引用e会指向这个事件对象),然后注册的事件监听器会自动触发(这里的匿名内部类对象就是注册的监听器),并调用指定方法actionPerformed,对产生的事件进行处理。

2.事件源、事件对象、事件监听器
1)事件源
AWT和Swing中的几乎所有的组件都可以作为事件源,注意容器也是一种组件。
例如:窗口、面板、按钮、输入框、下拉类别的菜单、单选复选框、标签、滚动条、进度条等等

例如:AWT和Swing中的组件都是java.awt.Component类的子类型,Component类中定义了很多所有组件都可以调用的方法,这些方法中有很多是这种形式的:addXxxxListener
这些方法就是给组件中注册事件监听器的方法,只是【不同类型的事件】需要使用【不同类型的监听器】来监听,所以不同的addXxxxListener方法就表示给组件添加相应的事件监听器。(Xxxx代表事件的类型)

2)事件对象及其对应的处理接口(也就是事件监听器)
注:事件处理器都被定义为了接口,思考为什么都定义为接口

java.util.EventObject类
public class EventObject extends Object{}

该类是java中所有事件对象的父类型。
该类中有一个非常重要的方法:getSource
public Object getSource(){...}
该方法返还的对象是产生当前事件的事件源
例如:当前使用鼠标点击按钮btn的时候,会产生一个事件对象e,这个对象e就表示鼠标点击的事件,同时e也是EventObject类型的对象,调用getSource方法可以得到产生事件的事件源,也就是我们点击的那个按钮btn.

java.awt.Event类
public class Event extends Object{..}
在Java1.1和以后的版本中该类已被废弃,由AWTEvent类及其子类所取代.

java.awt.AWTEvent类
public abstract class AWTEvent extends EventObject{...}
该类是所有AWT事件的父类型,此类及其子类取代了原来的 java.awt.Event类

java.awt.event.ActionEvent类
public class ActionEvent extends AWTEvent{...}
动作事件类,单击按钮、选择菜单项或在文本框中按回车时可产生此事件对象。
注:定时器Timer 也可以产生ActionEvent类型的事件

可以处理该类型事件的监听器接口:ActionListener
注:ActionListener是一个很通用的接口,可以处理很多种组件上面产生的事件.
例如: ActionEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

JButton btn = new JButton("测试");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("hello");
}
});

panel.add(btn);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.AdjustmentEvent类
public class AdjustmentEvent extends AWTEvent{..}
调整事件类,当改变滚动条滑块位置时可产生此事件对象。

该类代表由Adjustable类型对象所发出的调整事件。主要针对的是滚动条,Scrollbar和JScrollbar都是Adjustable接口的实现类。

可以处理该类型事件的监听器接口:AdjustmentListener
例如: AdjustmentEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

JScrollBar bar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 0, 0, 100);
bar.setPreferredSize(new Dimension(100, 20));
bar.addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println(e.getValue());
}
});

panel.add(bar);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.ComponentEvent类
public class ComponentEvent extends AWTEvent{...}
组件事件类,表示组件被移动、大小被更改或可见性被更改的事件,同时它也是其他组件事件的父类:
java.awt.event.ContainerEvent
java.awt.event.FocusEvent
java.awt.event.WindowEvent
..
这些都是它的的子类

可以处理该类型事件的监听器接口:ComponentListener
该接口中有四个抽象方法:
componentMoved组件移动时被调用
componentResized组件缩放时被调用
componentShown组件显示时被调用
componentHidden组件隐藏时被调用
例如:调用jFrame.setVisible(false);

例如:ComponentEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

jFrame.addComponentListener(new ComponentListener() {
public void componentShown(ComponentEvent e) {
System.out.println("shown");
}
public void componentHidden(ComponentEvent e) {
System.out.println("Hidden");
}
public void componentResized(ComponentEvent e) {
System.out.println("Resized");
}
public void componentMoved(ComponentEvent e) {
System.out.println("Moved");
}
});

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.ContainerEvent类
public class ContainerEvent extends ComponentEvent{..}
容器事件类,容器中因为添加或移除组件而更改的事件。

可以处理该类型事件的监听器接口:ContainerListener
接口中有俩个方法:
componentAdded添加组件时被调用
componentRemoved移除组件时被调用

例如:ContainerEventTest.java

JFrame jFrame = new JFrame();
final JPanel panel = new JPanel();

JButton btn = new JButton("点击");
final JButton test = new JButton("测试");

btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.add(test);
//在运行中动态添加组件
//需要调用容器的validate和repaint
//或者是调用容器的revalidate方法
//否则动态添加的组件不显示
//panel.validate();
//panel.repaint();
panel.revalidate();
}
});

panel.addContainerListener(new ContainerListener() {

@Override
public void componentRemoved(ContainerEvent e) {
System.out.println("removed");
}

@Override
public void componentAdded(ContainerEvent e) {
System.out.println("Added");
}
});

panel.add(btn);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.WindowEvent类
public class WindowEvent extends ComponentEvent{..}
窗口事件类,窗口打开、关闭等操作是会创建该事件对象。

可以处理该类型事件的监听器接口:WindowListener
该接口中有七个方法:
windowOpened窗口打开后被调用
windowClosed窗口关闭后被调用
windowClosing窗口关闭时被调用
windowActivated窗口激活时被调用
windowDeactivated窗口失去焦点时被调用
windowIconified窗口最小化时被调用
windowDeiconified最小化窗口还原时被调用

例如:WindowEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

jFrame.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {}
public void windowIconified(WindowEvent e) {
System.out.println("最小化窗口");
}
public void windowDeiconified(WindowEvent e) {
System.out.println("最小化窗口被还原");
}
public void windowDeactivated(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
});

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.FocusEvent类
public class FocusEvent extends ComponentEvent{...}
焦点事件类,当组件获得或者失去焦点的时候回产生该类型的事件对象。

可以处理该类型事件的监听器接口:FocusListener
该接口中有俩个方法:
focusGained组件获得焦点时被调用
focusLost组件失去焦点时被调用

例如:FocusEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

JTextField field = new JTextField(10);
JButton btn = new JButton("test");

field.addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
System.out.println("失去焦点");
}
public void focusGained(FocusEvent e) {
System.out.println("获得焦点");
}
});

panel.add(field);
panel.add(btn);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.ItemEvent类
public class ItemEvent extends AWTEvent{..}
选择事件类,选择复选框、选项框、单击列表框等时会产该事件对象。

可以处理该类型事件的监听器接口:ItemListener

例如:ItemEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

JCheckBox jck = new JCheckBox("自动登录");
jck.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
System.out.println(e.getStateChange());
}
});
panel.add(jck);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

注:
item的状态发生改变时触发该事件,item在这里的状态有两个,Selected 和 deSelected(即选中和未被选中),所以,当改变"下拉列表"中被选中的项的时候,其实是触发了两次事件,第一次是上次被选中的项的 State 由 Selected 变为 deSelected ,即取消选择, 第二次是本次被选中的项的 State 由 deSelected 变为 Selected ,即新选中,所以,这时候的 ItemStateChanged 事件中的代码要被执行两次了。
这种情况做一个判断即可
if(e.getStateChange() == ItemEvent.SELECTED){
   //要执行的代码
  }

java.awt.event.TextEvent类
public class TextEvent extends AWTEvent{..}
文本内容类,组件中的文本已改变时会产生该事件对象。

可以处理该类型事件的监听器接口:TextListener

例如:TextEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

TextField field = new TextField(10);
field.setText("hello");
field.addTextListener(new TextListener() {
@Override
public void textValueChanged(TextEvent e) {
System.out.println("改变了");
}
});

panel.add(field);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

注:如果是JTextField,那么需要这样监听内容的改变:
JTextField field = new JTextField(10);
field.getDocument().addDocumentListener(new DocumentListener() {
public void removeUpdate(DocumentEvent e) {

}
public void insertUpdate(DocumentEvent e) {

}
public void changedUpdate(DocumentEvent e) {

}
});

java.awt.event.KeyEvent类
public class KeyEvent extends InputEvent{..}
键盘事件类,键盘输入的时候会产生此事件对象。
注:InputEvent是ComponentEvent的子类,ComponentEvent类在上面已经介绍过了。
public abstract class InputEvent extends ComponentEvent {}

可以处理该类型事件的监听器接口:KeyListener
该接口中有三个方法:
keyPressed键按下时被调用
keyReleased键释放时被调用
keyTyped键入某个键时被调用(F1等功能按键时不会触发)

注:KeyEvent类中定义了很多静态常量,几乎把键盘上所以的按键都表示出来了。
例如:KeyEvent.VK_ENTER表示回车键,VK指的是Virtual-Key(虚拟键码VK值)

例如:KeyEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

JTextField field = new JTextField(10);

field.addKeyListener(new KeyListener() {

@Override
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped "+e.getKeyCode()+" "+e.getKeyChar());
}

@Override
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased "+e.getKeyCode());
}

@Override
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed "+e.getKeyCode());
}
});

panel.add(field);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

java.awt.event.MouseEvent类
public class MouseEvent extends InputEvent{..}
鼠标事件类,当鼠标在组件中发生鼠标动作的时候会产生此事件对象。

有三个接口可以处理该类型事件:
MouseListener接口
MouseMotionListener接口
MouseWheelListener接口

MouseListener接口中有五个方法:
mouseClicked 鼠标单击时被调用
mouseEntered 鼠标进入时被调用
mouseExited 鼠标离开时被调用
mousePressed 鼠标键按下时被调用
mouseReleased鼠标键释放时被调用

MouseMotionListener接口中有俩个方法:
mouseMoved 鼠标移动时被调用
mouseDragged鼠标拖拽时被调用

MouseWheelListener接口中有一个方法:
mouseWheelMoved 鼠标滚轮滚动时被调用

例如:MouseEventTest.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

panel.addMouseListener(new MouseListener() {
public void mouseReleased(MouseEvent e) {
System.out.println("mouseReleased");
}
public void mousePressed(MouseEvent e) {
System.out.println("mousePressed");
}
public void mouseExited(MouseEvent e) {
System.out.println("mouseExited");
}
public void mouseEntered(MouseEvent e) {
System.out.println("mouseEntered");
}
public void mouseClicked(MouseEvent e) {
System.out.println("mouseClicked");
}
});

panel.addMouseMotionListener(new MouseMotionListener() {
public void mouseMoved(MouseEvent e) {
System.out.println("mouseMoved");
}
public void mouseDragged(MouseEvent e) {
System.out.println("mouseDragged");
}
});

panel.addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent e) {
System.out.println("mouseWheelMoved");
}
});

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(panel);
jFrame.setVisible(true);

3.适配器 Adapter
很多监听器接口中都定义了很多个方法,每个方法负责处理一种产生事件的情况,我们编写实现类的时候就需要实现监听器接口中的所有方法,但是很多时候我们其实只需要调用接口中的一个方法,但是由于语法要求我们还是必须把接口中的所有抽象全都实现了。
例如: 点击按钮输出hello world
JButton btn = new JButton("test");
btn.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
System.out.println("hello world");
}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
});

使用了MouseListener接口的匿名内部类对象,并且五个方法全都实现了,但是其实我们只需要调用mouseClicked方法.

为了处理这个代码中出现的情况,又引入了接口的适配器类:XxxxAdapter

MouseAdapter实现了MouseListener, MouseWheelListener, MouseMotionListener三个接口,并且把接口中抽象方法全都进行了空实现,将来我们只需要创建MouseAdapter类的匿名内部类然后重写我们想调用的方法即可
例如: 点击按钮输出hello world
JButton btn = new JButton("test");
btn.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("hello world");
}
});

除了MouseAdapter实现MouseListener, MouseWheelListener, MouseMotionListener三个接口,是一个适配器类之外,还有其他的一些适配器类:

WindowAdapter适配器类实现了WindowListener, WindowStateListener, WindowFocusListener三个接口

ComponentAdapter适配器类实现了ComponentListener接口

ContainerAdapter适配器类实现了ContainerListener接口

FocusAdapter适配器类实现了FocusListener接口

KeyAdapter适配器类实现了KeyListener接口

MouseMotionAdapter适配器类实现了MouseMotionListener接口

HierarchyBoundsAdapter适配器类实现了HierarchyBoundsListener接口

4.定时器Timer
javax.swing.Timer类,可以定时触发事件(ActionEvent),调用监听器的指定方法。

例如:TimerTest1.java TimerTest2.java

JFrame jFrame = new JFrame();
JPanel panel = new JPanel();

JPanel north = new JPanel();
JButton startBtn = new JButton("开始");
JButton endBtn = new JButton("停止");

final Canvas canvas = new Canvas();

final Timer timer = new Timer(500,new ActionListener() {
private int count;
@Override
public void actionPerformed(ActionEvent e) {
if(count*10>=canvas.getWidth()){
return ;
}
Graphics g = canvas.getGraphics();
g.drawLine(count*10, 0, count*10, canvas.getWidth());
count++;
}
});

startBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
endBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timer.stop();
}
});

north.add(startBtn);
north.add(endBtn);

panel.setLayout(new BorderLayout());
panel.add(canvas);

jFrame.add(north,BorderLayout.NORTH);
jFrame.add(panel);

jFrame.setSize(400, 400);
jFrame.setLocation(700, 300);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);

5.让当前类实现监听器接口
当前对象this就成为了监听器对象
例如:
public class Test extends JFrame implements ActionListener{
private static final long serialVersionUID = 1L;

private JPanel jPanel;
private JButton btn;

public Test() {
setBounds(700, 500, 500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
initComponet();
setVisible(true);
}

private void initComponet(){
//初始化组件
jPanel = new JPanel();
btn = new JButton("测试");

//设置布局管理器并添加组件
jPanel.add(btn);

add(jPanel);

//给组件添加事件监听器
btn.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
System.out.println("hello world");
}

public static void main(String[] args) {
new Test();
}
}

java_day09_GUI事件的更多相关文章

  1. JNI详解---从不懂到理解

    转载:https://blog.csdn.net/hui12581/article/details/44832651 Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 C ...

  2. Jquery的点击事件,三句代码完成全选事件

    先来看一下Js和Jquery的点击事件 举两个简单的例子 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&q ...

  3. 关于 Chrome 浏览器中 onresize 事件的 Bug

    我在写插件时用到了 onresize 事件,在反复地测试后发现该事件在 Chrome 及 Opera(内核基本与 Chrome 相同,以下统称 Chrome)浏览器打开时就会执行,这种情况也许不能算作 ...

  4. MVVM设计模式和WPF中的实现(四)事件绑定

    MVVM设计模式和在WPF中的实现(四) 事件绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  5. C++中的事件分发

    本文意在展现一个C++实现的通用事件分发系统,能够灵活的处理各种事件.对于事件处理函数的注册,希望既能注册到普通函数,注册到事件处理类,也能注册到任意类的成员函数.这样在游戏客户端的逻辑处理中,可以非 ...

  6. 移动端IOS点击事件失效解决方案

    解决方案 解决办法有 4 种可供选择: 1 将 click 事件直接绑定到目标元素(即 .target)上 2 将目标元素换成 <a> 或者 button 等可点击的元素 3 将 clic ...

  7. Android笔记——Button点击事件几种写法

    Button点击事件:大概可以分为以下几种: 匿名内部类 定义内部类,实现OnClickListener接口 定义的构造方法 用Activity实现OnClickListener接口 指定Button ...

  8. HTML 事件(一) 事件的介绍

    本篇主要介绍HTML中的事件知识:事件相关术语.DOM事件规范.事件对象. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三 ...

  9. HTML 事件(二) 事件的注册与注销

    本篇主要介绍HTML元素事件的注册.注销的方式. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流.事件委托 4. ...

随机推荐

  1. 每个开发者都应该知道的SOLID原则

    每个开发者都应该知道的SOLID原则 单一职责原则(SRP) 它为什么违反了 SRP? 这种设计将来会带来什么问题? 开闭原则(OCP) 如何使它(AnimalSound)符合 OCP? 里氏替换原则 ...

  2. C#.NET中对称和非对称加密、解密方法汇总--亲测可用

    C#.NET中对称和非对称加密.解密方法汇总--亲测可用   在安全性要求比较高的系统中都会涉及到数据的加密.解密..NET为我们封装了常用的加密算法,例如:MD5,DES,RSA等.有可逆加密,也有 ...

  3. rocksdb wiki文档阅读笔记

    由于是英文文档,不做笔记过一阵就忘了,现在把关键点记录到这,开发的时候使用. 具体wiki地址:https://github.com/facebook/rocksdb/wiki 1)Column Fa ...

  4. 【Java】生成随机的手机号码并输出到文件

    import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.R ...

  5. C# 关于App.config

    App.config是winfrom等程序的应用程序配置文件,用来存放一些参数. app.config只会在应用程序启动时加载一次. 当程序在运行中修改app.config中的参数是不会生效,必须要重 ...

  6. Django组件-admin

    一. admin组件的使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INST ...

  7. 加入域之后,【Internet 时间】选项没有了

    这是加入域之前的截图,这时可以看见[Internet 时间]选项. 这是加入域之后的截图,这时就看不到[Internet 时间]选项了. 那这到底是为什么呢?别急,结合概念一看就明白啦. NTP全称网 ...

  8. Linux服务器感染kerberods病毒 | 挖矿病毒查杀及分析 | (curl -fsSL lsd.systemten.org||wget -q -O- lsd.systemten.org)|sh)

    概要: 一.症状及表现 二.查杀方法 三.病毒分析 四.安全防护 五.参考文章 一.症状及表现 1.CPU使用率异常,top命令显示CPU统计数数据均为0,利用busybox 查看CPU占用率之后,发 ...

  9. JQ scrollTop 无效的场景

    先要设置DOM为显示,然后在设置scrollTop,先后顺序不能调换.

  10. 如何写出优雅耐看的JavaScript代码

    参考链接:https://segmentfault.com/a/1190000020444918?utm_medium=hao.caibaojian.com&utm_source=hao.ca ...