现在的位置: 首页 > web前端 > 正文

用JavaScript完成页面滚动、点击和翻页操作

2020年02月12日 web前端 ⁄ 共 3799字 ⁄ 字号 评论关闭

  本文将会JavaScript记录事件对象进行一次实战,要完成的动作包括滚动、点击和翻页。


  一、滚动


  滚动是通过修改容器元素的scrollTop属性实现的,期间会进行一系列的计算,而每次滚动都会包含一个个小的偏移动作,为了让这些动作能有序进行,自定义了一个Promise,如下所示。


  /**


  * 简易Promise


  */


  var Promise = {


  fns: [],


  then: function(fn) {


  this.fns.push(fn);


  return this;


  },


  resolve: function() {


  if (this.fns.length == 0) return;


  var fn = this.fns.splice(0, 1);


  fn[0] && fn[0].call(this);


  }


  };


  为了让滚动表现的更加顺滑,采用了requestAnimationFrame()方法,滚动的方向分为三种,分别是向上、向下或待机,如下所示。


  /**


  * 随机整数


  */


  var Util = {


  random: function(max) {


  return Math.floor(Math.random() * max);


  }


  };


  /**


  * 随机滚动


  * container 容器元素


  */


  function scrollTopBottom(container) {


  var num = Util.random(10);


  for (var i = 0; i < num; i++) {


  (function(count) {


  Promise.then(function() {


  var direction, //滚动方向


  destination, //滚动的目标位置


  current, //当前滚动距离


  slide = 0; //滚动距离


  destination = Util.random(2000);


  current = container.scrollTop;


  direction = Util.random(3);


  (function moveInner() {


  switch (direction) {


  case 0: //向上滚动


  current += 10;


  break;


  case 1: //向下滚动


  current -= 10;


  if (current < 0) current = 0;


  break;


  default: //保持原地


  break;


  }


  slide += 10; //执行滚动


  console.log(count, slide, current, destination);


  container.scrollTop = current;


  if (slide <= destination && current > 0) {


  window.requestAnimationFrame(moveInner); //顺滑的滚动


  } else {


  Promise.resolve(); //执行下一个动作


  }


  })();


  });


  })(i);


  }


  Promise.resolve(); //开始滚动


  }


  滚动的容器元素多变,可能是body,也可能是根元素或者是其它元素,具体得视页面而定,示例页面采用的是根元素,如下所示。


  /**


  * document.documentElement


  * document.body


  */


  scrollTopBottom(document.documentElement);


  虽然完成了自动滚动,但当前的代码无法精度控制,例如难以配置成第几秒向上或向下滚动,或者指定滚动到真实用户会停留的位置的时间。


  二、点击


  在触发点击事件时,需要指定一些元素。目前的坐标是随机生成的,每次会遍历元素,当坐标在元素范围内时,才派发事件,完成点击,如下所示。MouseEvent中的clientX、pageX等属性可参考《 触屏touch事件记录 》中的记录。


  /**


  * 点击


  */


  function click() {


  var links = document.querySelectorAll("img"), //指定要触发的元素


  x = Util.random(window.outerWidth), //随机X坐标


  y = Util.random(document.body.scrollHeight), //随机Y坐标


  clientY = y > window.outerHeight ? (y - window.outerHeight) : y;


  var event = new MouseEvent("click", {


  bubbles: true, //能够冒泡


  cancelable: true, //可以取消事件


  view: window, //窗口


  clientX: x,


  clientY: clientY, //相对于视口的垂直偏移


  pageX: x,


  pageY: y //包含垂直滚动的偏移


  });


  [].forEach.call(links, function(value, key) {


  var rect = value.getBoundingClientRect();


  //判断当前坐标是否在元素范围内


  if(x >= rect.left && x<=rect.right && y>=rect.top && y<=rect.bottom) {


  console.log(x, y);


  value.dispatchEvent(event); //派发事件


  }


  });


  }


  function runClick() {


  for (var j = 0; j < 50; j++) {


  (function(j) {


  setTimeout(function() {


  click(); //随意点击页面


  }, 2000 * j); //不集中在一个时间执行


  })(j);


  }


  }


  虽然完成了自动点击,但还不够灵活。当要触发的动作不是由指定的元素触发的时,这段脚本就起不了作用,并且手机屏幕尺寸众多,难以精确的在某一指定区域内点击。


  由于很依赖事件类型,因此当绑定的动作不在该事件中时,代码也会失效。如果要触发页面监测的请求,那么不得不先去翻源码,搜寻触发事件。


  三、翻页


  现在很多活动页面都是以全屏翻页的形式出现,通过touchstart、touchmove和touchend三个事件,就能模拟出手指滑动的效果,方向既可以是从下到上,也可以是从右往左,下面的代码采用了前者。使用柯里化的方式减少了touch()函数的参数,TouchEvent中的touches和targetTouches参数,也可以参考《 触屏touch事件记录 》中的记录。


  /**


  * 竖屏翻页


  */


  var identifier = 0,


  eventType = ["touchstart", "touchmove", "touchend"];


  function slide(container) {


  var x = Util.random(window.outerWidth),


  y = 300,


  currying = touch(container, x, y);


  currying(eventType[0]);


  currying(eventType[1]);


  currying(eventType[2]);


  }


  function touch(container, x, y) {


  var interval = 100; //滑动距离


  return function(type) {


  identifier++;


  if (type == eventType[1]) { //touchmove事件更改Y坐标


  y -= interval;


  }


  var t = new Touch({


  identifier: identifier,


  target: container,


  clientX: x,


  clientY: y,


  pageX: x,


  pageY: y


  });


  console.log(`${identifier}, ${type} x: ${x}, y: ${y}`);


  var event = new TouchEvent(type, {


  touches: [t],


  targetTouches: [t]


  });


  container.dispatchEvent(event);


  };


  }


  /**


  * 假设滑动插件是swiper.js


  * 那么取其容器作为slide()的参数传入


  */


  setInterval(function() {


  slide(document.querySelector(".swiper-container"));


  }, 2000);


  示例中使用的是swiper触屏滑动插件,当换成其他插件时,容器就需要跟着改变。


  上述所有自动化操作都是基于DOM结构完成的,水能载舟亦能覆舟,无法跳出DOM的限制,就会导致一系列的问题,例如针对不同页面的结构要做单独的分析、动作精度难以控制、真实的用户轨迹难以模拟、代码不够灵活难以复用。


  在实际情况中,还有很多复杂的动作(例如答题、填表单等),光靠上述这点代码是远远不够的,目前还做不到像按键精灵那样在屏幕上录制行为,这么简洁。

抱歉!评论已关闭.