注册
web

心血来潮,这次我用代码“敲”木鱼

技术栈


面对这种寿命短,后期也基本不需要维护的项目(更没有复杂的网络请求一说),本篇文章直接使用原生JavaScript进行开发。或者您也可以尝试一下低代码



关于低代码,您大可放心的阅读此篇干货文章《低代码都做了什么?(为什么?怎么实现Low-Code?)》




至于TypeScript,您可以通过《谈谈写TypeScript实践而来的心得体会》这篇文章快速上手或进阶TS



实现


页面布局


wooden_fish_page_html.png


图中右侧标出了三个部分:



  1. img标签用于指定木鱼的图片url地址,在木鱼进行缩放时,对该标签增加/删除css类名即可
  2. 每次敲击时所产生的文字由p标签生成,且所有的p标签都存在于div标签之下
  3. audio标签会在敲击时播放声音


本篇文章不会涉及具体的Html、Css部分。如有疑问,请在此项目的GitHub中找到答案



逻辑部分


准备工作


通过JavaScript获取要操作的真实dom


const dom = {
// 木鱼
woodenFish: document.querySelector("img"),
// 文字浮层
text: document.querySelector(".w-f-c-text"),
// 音频
audio: document.querySelector("audio")
}
复制代码

木鱼缩放


这里的思路是敲击时给img追加一个带有css animation的样式类,该animation的作用是让木鱼进行一次缩放,例如


.w-f-c-i-size {
/** 这里的animation只会执行一次缩放,所以后面会通过增加/删除该类名来达到可以进行n次缩放的效果 */
animation: wooden-fish-size 0.3s;
}

@keyframes wooden-fish-size {
0% {
transform: scale(1);
}
50% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
复制代码

样式搞定之后,通过原生JavaScript提供的dom classList进行css样式类名的增加与删除。dom classList共有四个方法:



  1. add:在指定节点上增加一个样式类名
  2. remove:在指定节点上删除一个样式类名
  3. toggle:在指定节点A上若已有样式类名a,则将a删除;若没有样式类名a,则添加类名a
  4. replace:将指定节点上的样式类名替换为另一个样式类名。效果同String##replace一致

const woodenFish = {
// 封装一个用于增加/删除类名的方法
className(type) {
dom.woodenFish.classList[type]("w-f-c-i-size")
},
size() {
this.className("add")
setTimeout(() => this.className("remove"), 300)
}
}
复制代码

size方法用于进行一次木鱼的缩放。调用该方法时,首先为img标签增加类w-f-c-i-size,在300毫秒后,再将该类名移除


为什么是300毫秒?因为css animation的持续时间为300毫秒


需要注意的是,size方法中的thiswoodenFish对象,所以this.className就相当于woodenFish.className



关于this或其它JavaScript的问题,您可以在《JavaScript每日一题》专栏中找到对应的题目进行练习



文字浮层


const woodenFish = {
className() {},
size() {},
createText() {
const p = document.createElement("p")
p.innerText = "功德+1"
dom.text.appendChild(p)
}
}
复制代码

createText方法用于创建一个p标签,该标签的文字内容为“功德+1”,随后将该标签追加在div下即可


小tip:JSX(或react)中书写HTML类型的注释


博主在此刻书写document.createElement这个原生方法时,突然想到了最近用到的一个原生属性outerHTML,该属性与innerHTML的区别就不再赘述。在JSX中书写html类型的注释,使用大括号的形式({/** */})是不可以的,因为在编译时这些东西都会被扔掉,此时可以使用由React提供的dangerouslySetInnerHTML属性,但体验感不太好。所以可以使用ouertHTML配合ref来解决,vue同理,例如:


const HtmlComment: FC<HtmlCommentType> = ({ children }) => {
const virtual = useRef<HTMLSpanElement>(null)
useEffect(() => {
virtual.current!.outerHTML = `<!-- ${children} -->`
}, [])
return <span ref={virtual} />
}
复制代码

H5控制手机震动


const vibrate = () => {
const navigator = window.navigator
if (!("vibrate" in navigator)) return
navigator.vibrate =
navigator.vibrate ||
navigator.webkitVibrate ||
navigator.mozVibrate ||
navigator.msVibrate
if (!navigator.vibrate) return
// 上面的代码全是进行兼容性判断,只有下面这一行是发起手机震动的API
navigator.vibrate(300)
}
复制代码

像发起手机震动这类Api,首先就要进行兼容性判断,所以上面vibrate方法的90%部分都在进行兼容性判断。注意,window.navigator提供了一个用于发起设备震动的方法,即window.navigator.vibrate


window.navigator.vibrate方法的参数:



  1. 一个number类型的值

这种方式表示震动持续多长时间,例如window.navigator.vibrate(300),则表示震动持续300毫秒



  1. 一个number类型的数组

这种方式表示震动、暂停间隔的时间。例如window.navigator.vibrate([100, 30, 100]),则表示先震动100毫秒,随后暂停30毫秒,然后再震动100毫秒


window.navigator.vibrate方法在震动成功时返回true,否则返回false


vibrate兼容性


vibrate.png


浏览器全屏操作


const toggleFullScreen = () => {
if (!document.fullscreenElement)
return document.documentElement.requestFullscreen()
if (!document.exitFullscreen) return
document.exitFullscreen()
}

document.addEventListener("keydown", (e) =>
e.keyCode == 13 ? toggleFullScreen() : false
)
复制代码

toggleFullScreen方法会在全屏或非全屏之间来回切换,用到了以下属性/方法:



  1. document.fullscreenElement 返回当前正在以全屏模式显示的元素,如果没有,则返回null
  2. document.documentElement.requestFullscreen 用于发起全屏请求。若全屏请求成功,则该函数返回成功的Promise对象,否则返回失败的Promise对象。


在全屏成功时,全屏显示的元素会触发fullscreenchange事件;类似于输入框在输入时会触发onchange事件




  1. document.exitFullscreen 方法用于使当前元素退出全屏模式

随后为document绑定keydown事件,如果按下了回车键,则在全屏/非全屏之间切换,否则不做出任何操作


音频事件操作


之前博主在写播放器的时候就发现音频的属性、方法、事件很多很多,所以此处只列举两个本项目中用到的方法



  1. play()   使播放开始
  2. pause() 使播放暂停

制作完成


通过以上几个步骤就已经完成了所有要用到的东西,最后只需为木鱼注册“敲击”事件即可


dom.woodenFish.addEventListener("click", () => {
// 木鱼缩放
woodenFish.size()
// 创建文字浮层
woodenFish.createText()
// 播放敲击木鱼的声音
dom.audio.play()
// 发起手机震动
vibrate()
})
复制代码

文末


从一次心血来潮,到自己从0至1完成这个简单而有趣的小项目,无论是技术角度,还是个人收获角度来讲,都是收获满满!现在您可以通过以下两个地址来 “功德+1” :



  1. 在线使用地址
  2. GitHub地址,该仓库会持续制作一些package,欢迎Star !


由于时间匆忙,文中错误之处在所难免,敬请读者斧正。如果您觉得本篇文章还不错,欢迎点赞收藏和关注,我们下篇文章见!


作者:FuncJin
链接:https://juejin.cn/post/7199660596735164475
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册