动作(action),其本质是元素上的生命周期函数。它可用于譬如以下几个方面
- 与第三方库对接(在组件上集成第三方库的功能)
- 延迟加载图片
- 工具提示(tooltips)
- 添加自定义事件处理程序
`action 本质上只是一个普通的函数,它接收一个参数,就是当前元素的 DOM 节点对象
action 是一种为组件增强能力的特性,具有较强的封装性和复用性,可以将逻辑代码拆分到 JS 文件中供反复应用
// 一个action的定义 函数名任意
export function movable(node) {
// ... 第三方库或自定义事件处理程序的代码
return {
destroy() {
// ... destroy 函数会在元素被清除时调用,
// 可以在此做一些清理工作
}
}
}
<script>
import movable from './movable'
</script>
<!-- 通过 use 指令将自定义工具函数或第三方库应用到div上 -->
<div use:movable>Box</div>
<!-- 可以监听工具函数中的自定义事件 -->
<div
use:movable
on:movestart={e => console.log('move start...', e.detail)}
on:moving={e => console.log('moving', e.detail)}
on:moveend={() => console.log('move end...')}
>Box</div>
export default function movable(node) {
let moving = false
let x, y, left, top
function handleMove(e) {
if (moving) {
node.style.left = (e.clientX - x + left) + 'px'
node.style.top = (e.clientY - y + top) + 'px'
// 发送moving事件
// 使用node.dispatchEvent来发送对应的事件
// new CustomEvent(type, option) 是JS原生提供的创建自定义事件的方式
node.dispatchEvent(new CustomEvent('moving', {
detail: { x: e.clientX - x + left, y: e.clientY - y + top }
}))
}
}
function startMove(e) {
moving = true
x = e.clientX
y = e.clientY
left = parseInt(node.style.left) || 0
top = parseInt(node.style.top) || 0
// 发送movestart事件
node.dispatchEvent(new CustomEvent('movestart', { detail: {x:left, y:top}}))
}
function endMove() {
moving = false
// 发送moveend事件
node.dispatchEvent(new CustomEvent('moveend'))
}
window.addEventListener('mousemove', handleMove)
window.addEventListener('mouseup', endMove)
node.addEventListener('mousedown', startMove)
return {
destroy() {
window.removeEventListener('mousemove', handleMove)
window.removeEventListener('mouseup', endMove)
node.removeEventListener('mousedown', startMove)
}
}
}
附加参数
正如 transition 过渡效果和 animate 动画一样,动作(Action)也支持附带参数,动作函数会与它所在的元素一起被调用。
longpress.js
// action函数接收2个参数
// 参数1:绑定action的节点对象
// 参数2:绑定action的元素在使用的时候传入的参数
export function longpress(node, duration) {
let timer;
const handleMousedown = () => {
timer = setTimeout(() => {
node.dispatchEvent(
new CustomEvent('longpress')
);
}, duration * 1000);
};
const handleMouseup = () => clearTimeout(timer);
node.addEventListener('mousedown', handleMousedown);
node.addEventListener('mouseup', handleMouseup);
return {
destroy() {
node.removeEventListener('mousedown', handleMousedown);
node.removeEventListener('mouseup', handleMouseup);
}
};
}
<button
use:longpress={duration}
...
>按住我别放</button>
<!--
在action函数中,因为只有一个参数来接收外部传入的参数内容
所以如果需要传入多个参数的时候,只能将它们组合成一个对象来进行统一传入
-->
<button
use:longpress={{duration, spiciness}}
...
>按住我别放</button>
return {
destroy() {
node.removeEventListener('mousedown', handleMousedown);
node.removeEventListener('mouseup', handleMouseup);
},
// action对应的函数会在组件初始化的时候被执行
// 这意味着后续如果传入的参数的值发生了改变的时候,action对应函数是无法知晓的
// 此时可以在action的返回对象中增加update方法
// 每当参数有变,会立即调用update方法,并将参数的最新值作为参数传入
update(newDuration) {
duration = newDuration;
}
};