文章目录

  • 案例效果
  • 视图布局
    • 处理字体大小
    • HTML结构
    • CSS
  • 逻辑
  • 完整代码

案例效果

视图布局

处理字体大小

16px = 1.6rem

<script type="text/javascript">document.documentElement.style.fontSize = document.documentElement.clientWidth / 37.5 + 'px';
</script>

HTML结构

<div class="blank-cell-group"><div class="cell-item"><div class="wrapper"></div></div><div class="cell-item"><div class="wrapper"></div></div><div class="cell-item"><div class="wrapper"></div></div><div class="cell-item"><div class="wrapper"></div></div>
</div>

CSS

body {margin: 0;
}div {display: flex;flex-direction: column;
}.blank-cell-group {width: 100%;flex-direction: row;
}.blank-cell-group .cell-item {width: 25%;height: 25vw;padding: .5rem;box-sizing: border-box;
}.cell-item .wrapper {width: 100%;height: 100%;border: .1rem solid #ddd;box-sizing: border-box;border-radius: 50%;
}

逻辑

;(() => {const idioms = ['不足为训', '行尸走肉', '百里挑一', '两小无猜'], // 数据oBlankCellGroup = document.querySelector('.blank-cell-group'), oCharCellGroup = document.querySelector('.char-cell-group'); // 保存字的DOM父节点let charCollection = [], // 保存随机顺序的字blankAreas = [], // 保存目标选项盒子的起始坐标位置charAreas = [], // 保存所有选项的盒子的起始坐标位置resArr = [], // 保存目标盒子里字跟他对应的元素oChars = null, // 保存字的所有节点cellX,cellY,cellW,cellH,startX,startY,mouseX, // 按下点到盒子的X距离mouseY; // 按下点到盒子的Y距离const init = () => {charCollection = formatCharArr();render();oChars = oCharCellGroup.querySelectorAll('.cell-item .wrapper');oBlanks = oBlankCellGroup.querySelectorAll('.cell-item .wrapper');getAreas(oBlanks, blankAreas);getAreas(oChars, charAreas);bindEvent();}function render() {let list = '';charCollection.forEach((item, index) => {list += charCellTpl(item, index);})oCharCellGroup.innerHTML = list;}function bindEvent() {let oChar = null; // 单个字的DOM节点for(let i = 0; i < oChars.length; i++) {oChar = oChars[i];oChar.addEventListener('touchstart', handleTouchStart, false);oChar.addEventListener('touchmove', handleTouchMove, false);oChar.addEventListener('touchend', handleTouchEnd, false);}}function handleTouchStart(e) {// 拿到盒子的宽高cellW = this.offsetWidth;cellH = this.offsetWidth;// 拿到盒子的left跟topcellX = this.offsetLeft;cellY = this.offsetTop;// 拿到触点的x跟ystartX = e.touches[0].clientX;startY = e.touches[0].clientY;// 拿到触点到盒子的X跟Y定值mouseX = startX - cellX;mouseY = startY - cellY;// console.log(cellW, cellH)// console.log(mouseY, mouseX)// 设置盒子的宽高跟固定定位this.style.width = cellW / 10 + 'rem';this.style.height = cellH / 10 + 'rem';this.style.position = 'fixed';// 设置盒子的left 跟 topthis.style.left = cellX / 10 + 'rem';this.style.top = cellY / 10 + 'rem';}function handleTouchMove(e) {e.preventDefault();const moveX = e.touches[0].clientX,moveY = e.touches[0].clientY;cellX = moveX - mouseX;cellY = moveY - mouseY;// 设置盒子的left 跟 topsetPosition(this, {startX: cellX, startY: cellY});}function handleTouchEnd(e) {// 盒子的宽高let blankWidth = oBlanks[0].offsetWidth,blankHeight = oBlanks[0].offsetHeight;for(let i = 0; i < blankAreas.length; i++ ) {// 空的时候是empty,实值就是undefinedif(resArr[i] !== undefined) {continue;}let { startX, startY } = blankAreas[i];if((startX < cellX &&startY < cellY &&startX + blankWidth / 2 > cellX &&startY + blankHeight / 2 > cellY ) ||(startX + blankWidth / 2 < cellX + blankWidth &&startX + blankWidth > cellX + blankWidth &&startY + blankHeight / 2 > cellY &&startY < cellY)) {setPosition(this, { startX, startY });setResArr(this, i);if(resArr.length === 4) {setTimeout(() => {if(!checkResult()) {alert('答错了呢~')}else {alert('答对了~~~')}resetPosition();}, 1000)}return;}}const _index = Number(this.dataset.index); // 获取盒子的标识const charArea = charAreas[_index];setPosition(this, { ...charArea });}// 获取所有盒子的起始位置function getAreas(domCollection, arrWrapper) {let startX = 0,startY = 0,oItem = null;for(let i = 0; i < domCollection.length; i++) {oItem = domCollection[i];startX = oItem.offsetLeft;startY = oItem.offsetTop;// 其实保存的就是盒子的顶点坐标(左上角)arrWrapper.push({startX,startY})}}function formatCharArr() {let _arr = [];idioms.forEach(item => {_arr = _arr.concat(item.split(''));})return _arr.sort(randomSort);}function randomSort(a, b) {return Math.random() > 0.5 ? -1 : 1;}function charCellTpl(char, index) {return (`<div class="cell-item"><div class="wrapper"  data-index=${index}>${char}</div></div>`);}function setPosition (el, { startX, startY }) {el.style.left = startX / 10 + 'rem';el.style.top = startY / 10 + 'rem';}// 回到初始状态function resetPosition() {resArr.forEach(item => {const el = item.el,index = Number(el.dataset.index),{ startX, startY } = charAreas[index];setPosition(el, { startX, startY })})resArr = [];cellX = 0;cellY = 0;cellW = 0;cellH = 0;startX = 0;startY = 0;mouseX = 0; // 按下点到盒子的X距离mouseY = 0; // 按下点到盒子的Y距离init()}// 保存结果function setResArr (el, index) {resArr[index] = {char: el.innerText,el}}// 检查答案function checkResult () {let idiom = '';resArr.forEach(item => {idiom += item.char;})console.log(idiom)return idioms.find(item => item == idiom);}init();})();

完整代码

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title></title><script type="text/javascript">document.documentElement.style.fontSize = document.documentElement.clientWidth / 37.5 + 'px';</script><style type="text/css">body {margin: 0;}div {display: flex;flex-direction: column;}.char-cell-group {margin-top: 5rem;}.blank-cell-group,.char-cell-group {width: 100%;flex-direction: row;}.char-cell-group {/*换行*/flex-wrap: wrap; }.blank-cell-group .cell-item,.char-cell-group .cell-item{width: 25%;height: 25vw;padding: .5rem;box-sizing: border-box;}.cell-item .wrapper {width: 100%;height: 100%;border: .1rem solid #ddd;box-sizing: border-box;border-radius: 50%;}.char-cell-group .cell-item .wrapper {background-color: lightblue;font-size: 3rem;justify-content: center;align-items: center;color: white;}</style>
</head>
<body>
<div id="app"><div class="container"><div class="blank-cell-group"><div class="cell-item"><div class="wrapper"></div></div><div class="cell-item"><div class="wrapper"></div></div><div class="cell-item"><div class="wrapper"></div></div><div class="cell-item"><div class="wrapper"></div></div></div><div class="char-cell-group"></div></div>
</div>
<script type="text/javascript">;(() => {const idioms = ['不足为训', '行尸走肉', '百里挑一', '两小无猜'], // 数据oBlankCellGroup = document.querySelector('.blank-cell-group'), oCharCellGroup = document.querySelector('.char-cell-group'); // 保存字的DOM父节点let charCollection = [], // 保存随机顺序的字blankAreas = [], // 保存目标选项盒子的起始坐标位置charAreas = [], // 保存所有选项的盒子的起始坐标位置resArr = [], // 保存目标盒子里字跟他对应的元素oChars = null, // 保存字的所有节点cellX,cellY,cellW,cellH,startX,startY,mouseX, // 按下点到盒子的X距离mouseY; // 按下点到盒子的Y距离const init = () => {charCollection = formatCharArr();render();oChars = oCharCellGroup.querySelectorAll('.cell-item .wrapper');oBlanks = oBlankCellGroup.querySelectorAll('.cell-item .wrapper');getAreas(oBlanks, blankAreas);getAreas(oChars, charAreas);bindEvent();}function render() {let list = '';charCollection.forEach((item, index) => {list += charCellTpl(item, index);})oCharCellGroup.innerHTML = list;}function bindEvent() {let oChar = null; // 单个字的DOM节点for(let i = 0; i < oChars.length; i++) {oChar = oChars[i];oChar.addEventListener('touchstart', handleTouchStart, false);oChar.addEventListener('touchmove', handleTouchMove, false);oChar.addEventListener('touchend', handleTouchEnd, false);}}function handleTouchStart(e) {// 拿到盒子的宽高cellW = this.offsetWidth;cellH = this.offsetWidth;// 拿到盒子的left跟topcellX = this.offsetLeft;cellY = this.offsetTop;// 拿到触点的x跟ystartX = e.touches[0].clientX;startY = e.touches[0].clientY;// 拿到触点到盒子的X跟Y定值mouseX = startX - cellX;mouseY = startY - cellY;// console.log(cellW, cellH)// console.log(mouseY, mouseX)// 设置盒子的宽高跟固定定位this.style.width = cellW / 10 + 'rem';this.style.height = cellH / 10 + 'rem';this.style.position = 'fixed';// 设置盒子的left 跟 topthis.style.left = cellX / 10 + 'rem';this.style.top = cellY / 10 + 'rem';}function handleTouchMove(e) {e.preventDefault();const moveX = e.touches[0].clientX,moveY = e.touches[0].clientY;cellX = moveX - mouseX;cellY = moveY - mouseY;// 设置盒子的left 跟 topsetPosition(this, {startX: cellX, startY: cellY});}function handleTouchEnd(e) {// 盒子的宽高let blankWidth = oBlanks[0].offsetWidth,blankHeight = oBlanks[0].offsetHeight;for(let i = 0; i < blankAreas.length; i++ ) {// 空的时候是empty,实值就是undefinedif(resArr[i] !== undefined) {continue;}let { startX, startY } = blankAreas[i];if((startX < cellX &&startY < cellY &&startX + blankWidth / 2 > cellX &&startY + blankHeight / 2 > cellY ) ||(startX + blankWidth / 2 < cellX + blankWidth &&startX + blankWidth > cellX + blankWidth &&startY + blankHeight / 2 > cellY &&startY < cellY)) {setPosition(this, { startX, startY });setResArr(this, i);if(resArr.length === 4) {setTimeout(() => {if(!checkResult()) {alert('答错了呢~')}else {alert('答对了~~~')}resetPosition();}, 1000)}return;}}const _index = Number(this.dataset.index); // 获取盒子的标识const charArea = charAreas[_index];setPosition(this, { ...charArea });}// 获取所有盒子的起始位置function getAreas(domCollection, arrWrapper) {let startX = 0,startY = 0,oItem = null;for(let i = 0; i < domCollection.length; i++) {oItem = domCollection[i];startX = oItem.offsetLeft;startY = oItem.offsetTop;// 其实保存的就是盒子的顶点坐标(左上角)arrWrapper.push({startX,startY})}}function formatCharArr() {let _arr = [];idioms.forEach(item => {_arr = _arr.concat(item.split(''));})return _arr.sort(randomSort);}function randomSort(a, b) {return Math.random() > 0.5 ? -1 : 1;}function charCellTpl(char, index) {return (`<div class="cell-item"><div class="wrapper"  data-index=${index}>${char}</div></div>`);}function setPosition (el, { startX, startY }) {el.style.left = startX / 10 + 'rem';el.style.top = startY / 10 + 'rem';}// 回到初始状态function resetPosition() {resArr.forEach(item => {const el = item.el,index = Number(el.dataset.index),{ startX, startY } = charAreas[index];setPosition(el, { startX, startY })})resArr = [];cellX = 0;cellY = 0;cellW = 0;cellH = 0;startX = 0;startY = 0;mouseX = 0; // 按下点到盒子的X距离mouseY = 0; // 按下点到盒子的Y距离init()}// 保存结果function setResArr (el, index) {resArr[index] = {char: el.innerText,el}}// 检查答案function checkResult () {let idiom = '';resArr.forEach(item => {idiom += item.char;})console.log(idiom)return idioms.find(item => item == idiom);}init();})();
</script>
</body>
</html>

【原生JavaScript案例】拖拽回弹吸附 猜成语小游戏相关推荐

  1. Python基础,猜成语小游戏

    猜成语 闲的无事,无聊的写bug,突然觉得可以随便写个猜成语小游戏,正好可以解闷 Python随机库,random random是Python的随机库,有这样几个简单的用法 在使用random前要用i ...

  2. C++课程设计——猜成语小游戏

    问题描述 题目描述:成语是中国汉字语言词汇中一部分定型的词组或短句,是中国传统文化的一大特色,有固定的结构形式和固定的说法,表示一定的意义,在语句中是作为一个整体来应用的,承担主语.宾语.定语等成分. ...

  3. python成语游戏代码_Python基础,猜成语小游戏

    猜成语 闲的无事,无聊的写bug,突然觉得可以随便写个猜成语小游戏,正好可以解闷 Python随机库,random random是Python的随机库,有这样几个简单的用法 在使用random前要用i ...

  4. jQuery手机端看图猜成语小游戏代码

    下载地址 jQuery手机端看图猜成语小游戏.游戏介绍:给你一张图片,在下列文字里面选择组合一个成语,答对进入下一关游戏源码. dd:

  5. 原生javascript实现拖拽改变table表格行高(html)

    最近在做一个OA的项目,里面需要大量的表格操作.有一些是使用html中的table去模拟excel的功能,等项目做完,我会把这些好玩的功能抽取出来,做一个html的excel插件.   今天先和大家分 ...

  6. JAVA实现猜成语小游戏(作业记录)

    编写一个猜成语的小游戏. 要求:使用一个字符串数组来保存10个四字成语,例如: String [] idioms = {"凉拌黄瓜", "红烧肘子", -}; ...

  7. JavaScript:一个非常有趣的猜数小游戏

    文章目录 猜数字游戏 猜数字游戏 程序随机生成一个 1~ 50 之间的数字,并让用户输入一个数字, 如果大于该数字,就提示,数字大了,继续猜: 如果小于该数字,就提示数字小了,继续猜: 如果等于该数字 ...

  8. MATLAB 看图猜成语 小游戏

    文章目录 一,设置GUI界面 1.游戏的开始界面 2.游戏页面 二,界面的动态效果 1.开始游戏 2.游戏中的效果 三,游戏的主程序 四,源代码 1. 主程序 2.开始页面 3.游戏页面 一,设置GU ...

  9. 用python做C语言的猜数字游戏,[Python3 练习] 007 简单的猜数字小游戏

    题目:简单的猜数字小游戏 (1) 描述 程序随机生成一个数字,玩家用键盘输入所猜数字,在规定次数内猜对为胜. (2) 要求 程序随机生成一个 1 到 100 的自然数 有 7 次机会去猜 机会用尽之前 ...

最新文章

  1. 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记
  2. Android DDMS应用
  3. python 删除list中的第一个元素
  4. 浅析call和apply的不同
  5. java掉单_【Java】抄答案就是了,两套详细的设计方案,解决头疼的支付掉单问题...
  6. 正则表达式以什么开头以什么结尾_股票hk是什么意思,股票st开头是什么意思,新通联股票...
  7. mysql workbench 无法编辑_MySQL Workbench编辑表数据是只读的
  8. 吴恩达机器学习之线性逻辑回归实现部分
  9. sql中的while循环_SQL While循环:了解SQL Server中的While循环
  10. HTML 遮罩显示工具栏
  11. 9/28shell合集
  12. 原神3.4私服一键包搭建教程windows+linux
  13. 如何在线合并视频?合并视频这样做
  14. python复利计算_python:复利计算
  15. 【Arduino实验12 1602 LCD显示】
  16. 【日志审计与分析】centOS7 安装ELK平台
  17. 【51nod1299】监狱逃离(树形DP)
  18. map contract violation
  19. RHCSA——第八天
  20. C/C++笔试题(12)

热门文章

  1. 1050: 阶乘的累加和 C语言
  2. BERT入门教程学习心得 word embedding
  3. 鲁大师8月新机性能/流畅榜:最流畅“黑马”选手出现了
  4. 游戏变革者,集结在5G边缘
  5. 公式编号 制表位_制表符(公式居中,标号居右)
  6. 2022-2028全球滋补品行业调研及趋势分析报告
  7. Qt 5.4正式版发布,支持HTML5混合开发
  8. 写论文时如何快速的把文中的数字和英文替换文 Times New Roman
  9. 从零开始搭建一个GIS开发小框架(七)——GMap.Net组件WPF版本加载POI性能测试
  10. 李斌说2023年销量超过雷克萨斯,蔚来能做到吗?