浅谈 原生javaScript && react 实现全局触摸按钮(附带对addeventlistener的了解)
1.采用原生javaACript 实现全局触摸按钮
首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法。
因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位置,通过改变样式来改变按钮任意移动位置。所以就那了changedTouches里面的值。touches里面放的是touchstart的开始位置。用react的时候,touch事件会和click起冲突,导致链接点击有bug,所以需要那touchstart的值在touchend的时候做判断是点击事件还是触摸事件,来控制超链接的跳转。但是在普通h5中并没有这个问题,下面再细说。
这是html代码
- <div class="active" id="active">
- <a class="vote" id="vote" href="https://www.baidu.com"></a> //是全局可以触摸的对象,点击又可以做跳转
- </div>
css样式
- *{
- margin:;
- padding:;
- } //demo里面我就直接去掉所有默认的样式
- .active {
- width: 100%;
- height: 100%;
- background: #9ff5ee;
- }
- .vote {
- position: fixed;
- bottom:40px; //全局触摸按钮使用定位的样式,可是随时改变定位的坐标来控制任意移动
- right: 15px;
- width: 60px;
- height: 60px;
- border-radius: 50%;
- background: yellow;
- }
接下来是重点的javascript代码,顺便讲解一下(preventDefault()、stopPropagation()这些方法,ps其实是一边写博客一边学习,复习)
- window.onload=function(){ //当一个Web页面加载完成后就会触发执行window.onload 里的代码
- var vote=document.getElementById("vote");//通过id取按钮这个节点
- function handleTouchEvent(e) {
- //只跟踪一次触摸
- var width=document.documentElement.clientWidth,height=document.documentElement.clientHeight; //这里取屏幕的可视宽度和可视高度来控制按钮的最大最小访问
- switch (e.type) {
- case "touchstart": //触摸开始调用的方法
- console.log('start');
- break;
- case "touchend":
- console.log('end'); //触摸结束调用的方法,这里不用用到这两个方法,所以不做详情介绍
- break;
- case "touchmove":
- //全局触摸主要用到touchmove这个方法,touchmove过程中坐标会不断变化,取这个变化的坐标来控制当前那全局按钮#vote的坐标。使用style对象来修改目前的样式,其间做了一个控制,不让按钮可以移动上左下右任意方向的屏幕外我用了两层三目运算符来限制坐标的最小和最大值。
- document.getElementById("vote").style.left=parseInt(e.changedTouches[0].clientX) - 60 <= 0 || parseInt(e.changedTouches[0].clientX) >= width - 60 ? (parseInt(e.changedTouches[0].clientX) - 60 <= 0 ? 0 : width - 60) : parseInt(e.changedTouches[0].clientX);
- //左右方向,最小位置不小于按钮的直径,最大不超过屏幕的可视宽度减按钮直径,上下方向也是
- document.getElementById("vote").style.top=parseInt(e.changedTouches[0].clientY) - 60 <= 0 || parseInt(e.changedTouches[0].clientY) >= height - 60 ? (parseInt(e.changedTouches[0].clientY) - 60 <= 0 ? 0 : height-60) : parseInt(e.changedTouches[0].clientY);
- break;
- }
- }
- function clickA(e){
- e.preventDefault();//这里是点击事件,阻止了默认事件的触发,所以超链接不会跳转,没阻止的话超链接就会正常跳转了
- }
- vote.addEventListener("touchstart", handleTouchEvent, false);
- vote.addEventListener("touchmove", handleTouchEvent, false);
- vote.addEventListener("touchend", handleTouchEvent, false);
- vote.addEventListener("click", clickA, false);
- }
事件调用的方法有 attachEvent方法适用于IE addEventListener方法适用于FF
attachEvent只有两个参数,第一个参数为事件名称,第二个参数为接收事件处理的函数,因为是做h5的触摸,不需要做ie的兼容,所以没做全兼容。如果要做全兼容,如下
- //兼容所有浏览器的事件监听方法
- function(element, type, handler){
- if (element.addEventListener) {
- element.addEventListener(type, handler, false);
- }
- else
- if (element.attachEvent) {
- element.attachEvent("on" + type, handler);
- }
- else {
- element["on" + type] = handler;
- }
- }
上文demo中事件的调用采用了addEventListener这个方法,这个方法有三个参数,第一个参数表示事件名称(不含 on,如 "click");第二个参数表示要接收事件处理的函数;第三个参数是一个bool值,一般为false。第三个参数的作用设置事件为冒泡还是捕获,如果为false那就是冒泡bubbling,为true就是捕获capture,冒泡和捕获是什么呢,看图
两层div元素,而且都设定有click事件,一般来说,如果我在内层黄色的元素上click不只会触发黄色元素的click事件,还会同时触发红色元素的click事件,由内到外的触发就是冒泡bubbling,由外层div到内层div触发就是捕获。这时候如果想阻止这些冒泡和捕获事件的发生,就需要用到stopPropagation()方法了,IE中则使用e.cancelBubble = true阻止冒泡,该方法阻止目标元素的冒泡事件,但是会不阻止默认行为。浏览器的默认行为就需要用到preventDefault()方法来阻止默认事件,比如上文的阻止超链接的跳转。
阻止冒泡的效果如下
- function clickA(e){
- alert('aaaa')
- e.stopPropagation(); //点击a#vote按钮,如果没有加入该行,点击该事件会同时出发a#vote和div#active上面的事件,加入该行就可以阻止冒泡
- e.preventDefault();//这里是点击事情,阻止了默认事件的触发,所以超链接不会跳转,没阻止的话超链接就会正常跳转了
- }
- function clickDiv(e){
- alert('444')
- }
- document.getElementById("vote").addEventListener("click", clickA, false); //事件的调用
- document.getElementById("active").addEventListener("click", clickDiv, false);
以上为原生javascript的实现方法
2.react 实现全局触摸按钮(使用react+ES6语法,使用webpack打包工具)
react大体包含(组件 ,JSX, 虚拟DOM, 单向数据流);
JSX也就是HTML直接嵌套到JS代码里面,所以以下就没有所谓的html和js分开了。
我们首先还是来观察react+ES6的事件输出,根据前面原生的js我们知道移动端的触摸主要用了touches和changedTouches里面的值,用touches来取得初始的坐标位置,用changedTouches可以取得触摸后移动位置的坐标。除了这两个还有一个targetTouches保存着当前坐标。它们都属于TouchList
对象
TouchList
由Touch
对象构成的数组,通过event.touches
取到。一个Touch
对象代表一个触点,当有多个手指触摸屏幕时,TouchList
就会存储多个Touch
对象,前面说到的identifier
就用来区分每个手指对应的Touch
对象。
touches / changedTouches / targetTouches
touches
一个TouchList对象,包含当前所有接触屏幕的触点的Touch对象,不论 touchstart 事件从哪个elment上触发。
targetTouches
也是一个TouchList对象,包含了如下触点的 Touch 对象:touchstart从当前事件的目标element上触发
changedTouches
也是一个 TouchList 对象,对于 touchstart 事件, 这个 TouchList 对象列出在此次事件中新增加的触点。对于 touchmove 事件,列出和上一次事件相比较,发生了变化的触点。对于 touchend ,列出离开触摸平面的触点(这些触点对应已经不接触触摸平面的手指)。
touchend这里要特别注意,touches和targetTouches只存储接触屏幕的触点,要获取触点最后离开的状态要使用changedTouches ,但是在react单向数据流中,可以实时改变状态机state中的值,所以可以不断取得接触屏幕触点的位置来改变触摸对象的坐标,所以react里面可用touches和targetTouches在touchend和touchmove中
e.touches、e.targetTouches、e.changedTouches 的输出都如下图,都是Touch对象
react绑定事件处理函数---->触摸(React 标准化了事件对象,因此在不同的浏览器中都会有相同的属性。)
onTouchCancel
onTouchEnd
onTouchMove
onTouchStart
触摸只会在移动设备上产生。在使用触摸时,尝试着用onclick来处理同个元素上的点击事件,发现点击事件根本没反应。所以我就在onTouchEnd处理元素触摸后的结果。当元素触摸结束后位置没偏移,就可以当成是点击事件,处理点击事件要完成的任务。
接下来上代码。
- 'use strict';
- import React from 'react';
- import './index.less'; //这里用的都是es6的引入方式
- export default class Back extends React.Component {
- static defaultProps = {
- prefixCls: 'zm'
- };
- constructor() { //初始化state的工作要在constructor中完成。
- super();
- //在react中,无法获取dom节点,把要改变的值放在state状态机中
- this.state = {
- top: '76%', //触摸按钮初始位置(距离左边顶部的位置)
- left: '83%',
- startX: '', //触摸按钮初始的坐标
- startY: '',
- x: 0, //记录触摸按钮触摸后有无变化
- y: 0,
- height: document.documentElement.clientHeight, //屏幕可视宽高
- width: document.documentElement.clientWidth,
- };
- }
- handleStart(e){
- e.preventDefault();
- //前面原生js用的是touches,其实还有一个targetTouches,在这两个的输出结果是一致的。
- this.setState({ //当触摸开始时候,记录当时的坐标值,还有设置触摸变化的xy轴的变化为0,因为当新一轮触摸开始时候,必须重新设置,相当于初始化
- startX : e.targetTouches[0].clientX,
- startY : e.targetTouches[0].clientY,
- x:0,
- y:0,
- });
- }
- handleTouchMove(e) {
- const { startX, startY, width, height } = this.state;//取得初始坐标和屏幕可视宽高
- this.setState({
- //设置当前的坐标位置,思路和上面原生的一样,不过由于react有实时变化的状态机state,所以在此用touches,targetTouches
- //都可以来设置实时变化的值,不用用到changedTouches;
- left: parseInt(e.touches[0].clientX) - 48 <= 0 || parseInt(e.touches[0].clientX) >= width - 48 ? (parseInt(e.touches[0].clientX) - 48 <= 0 ? 0 : width - 48) : parseInt(e.touches[0].clientX),
- top: parseInt(e.touches[0].clientY) - 48 <= 0 || parseInt(e.touches[0].clientY) >= height - 48 ? (parseInt(e.touches[0].clientY) - 48 <= 0 ? 0 : height - 48) : parseInt(e.touches[0].clientY),
- x: e.touches[0].clientX - startX, //当前触摸点-初始坐标取得实时变化值
- y: e.touches[0].clientY - startY,
- });
- }
- handleTouchEnd (e) {
- const { x, y } = this.state;
- if (x == 0 && y == 0) { //触摸结束后,判断实时变化值有没变化,没变化则视为点击事件。
- window.location.href = '#';
- };
- }
- render() {
- const { prefixCls } = this.props;
- const { top, left, height, width } = this.state; //取得实时状态机state的值
- return (
- <div
- className="zm"
- style={{top:`${top}`,left:`${left}` }} //取得state的值实时改变触摸点的坐标位置
- onTouchStart={this.handleStart.bind(this)} //使用bind(this)改变函数作用域,不加上bind则this指向的是全局对象window而报错。
- onTouchMove={this.handleTouchMove.bind(this)}
- onTouchEnd={this.handleTouchEnd.bind(this)}
- />
- )
- }
- }
react中要注意的是使用touch时 click没反应,需要在touchend中做判断做处理
浅谈 原生javaScript && react 实现全局触摸按钮(附带对addeventlistener的了解)的更多相关文章
- 浅谈 原生javaScript&&react 实现全局触摸按钮(附带对addeventlistener的了解)
1.采用原生javaACript 实现全局触摸按钮 首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法. 因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位 ...
- 浅谈原生JavaScript实现remove()和recover()
利用原生JavaScript实现: 1.remove(selectors)删除指定的一个或一组元素. 2.recover(selectors)恢复刚才删除的元素. function remove(se ...
- 浅谈原生JavaScript的动画和特效
一.JavaScript中的动画原理 动画效果的实现总的来说可分为两种,一种是利用纯css实现,该方法在css3成熟后广泛应用:另外一种是通过JavaScript(或者一些封装的库如jQuery的an ...
- 浅谈前端JavaScript编程风格
前言 多家公司和组织已经公开了它们的风格规范,详细可參阅jscs.info,以下的内容主要參考了Airbnb的JavaScript风格规范.当然还有google的编程建议等编程风格 本章探讨怎样使用E ...
- 表单美化-原生javascript和jQuery多选按钮(兼容IE6)
前些天我们讲了下单选按钮的美化今天来做表单元素多选按钮的美化.我们的想法是:利用多选按钮是否被选中和是否不给选择的特性来为按钮的父元素添加对应的样式,就是说用什么的样式是由按钮的状态来决定. 用到的图 ...
- 浅谈控件(组件)制作方法一(附带一delphi导出数据到Excel的组件实例)(原创)
来自:http://blog.csdn.net/zhdwjie/article/details/1490741 -------------------------------------------- ...
- 浅谈React
浅谈react react是什么?其官网给出了明确定义:A JavaScript library for building user interfaces,一个用于构建用户界面的JavaScript库 ...
- 浅谈React数据流管理
引言:为什么数据流管理如此重要?react的核心思想就是:UI=render(data),data就是我们说的数据流,render是react提供的纯函数,所以用户界面的展示完全取决于数据层.这篇文章 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
随机推荐
- Fiddler安卓抓包详细教程
电脑端抓包一般图方便就用浏览器自带的,最近需要分析安卓一个APP的HTTP请求,尝试了wireshark(功能太强大了,然而我并不会用),tcpdump(用起来还是比较麻烦),网上搜了一下,还是使用F ...
- svn资源库url问题
今天连接svn资源库的时候一直出现 RA layer request failedsvn: Unable to connect to a repository at URL http://... sv ...
- Qt 汽车仪表 QWidget
今天是2016年的最后一个工作日,在这个最后工作日里面,和以为网友要了一点练手的素材文件,经过网友确认,不涉及商业机密,在这里分享一下,如侵权,请联系我删除. 先上程序运行图 这里显示数字,闪烁等都没 ...
- Git 使用 粗糙记录
版本控制应该是每一个开发人员应该会的东西,奈何,学校没有学习,随着写代码的时间的加长,越来月觉得版本控制的必要性了. 记得在实习的公司,同一痛的都是SVN. 至于GIt和SVN的区别,直接看连接 ht ...
- (原创)像极了爱情的详解排序二叉树,一秒get
排序二叉树(建立.查找.删除) 二叉树我们已经非常熟悉了,但是除了寻常的储存数据.遍历结构,我们还能用二叉树做什么呢? 我们都知道不同的遍历方式会对相同的树中产生不同的序列结果,排序二叉树就是利用二叉 ...
- CentOS环境安装JDK(二)
安装JDK-7u79-linux-x64 打开虚拟机,进入终端: 1.假设用户名是tianjiale(则需要进入管理员角色,既root) (1).将用户名tianjiale添加到sudoer列表中 提 ...
- C++ 学习笔记之——文件操作和文件流
1. 文件的概念 对于用户来说,常用到的文件有两大类:程序文件和数据文件.而根据文件中数据的组织方式,则可以将文件分为 ASCII 文件和二进制文件. ASCII 文件,又称字符文件或者文本文件,它的 ...
- Coursera: Internet History, Technology, and Security
课程网址:https://www.coursera.org/learn/internet-history 学习笔记: Week 1: History - Dawn of Early Computing ...
- 解决Mysql错误Too many connections的方法
MySQL数据库 Too many connections出现这种错误明显就是 mysql_connect 之后忘记 mysql_close:当大量的connect之后,就会出现Too many co ...
- 玩Vim
1)我一个脚本中粘贴的都是当年在vim下粘的东西,都是带行号的,我现在想把所有的行号都换成回车键,要怎么办呢? %s/[0-9]/^M/g 注:其中回车在vim的输入方法是ctrl+V,会得到^,此时 ...