diff --git a/packages/taro-components/src/components/canvas/index.js b/packages/taro-components/src/components/canvas/index.js index f7ec5e418787..0c1c0966fd85 100644 --- a/packages/taro-components/src/components/canvas/index.js +++ b/packages/taro-components/src/components/canvas/index.js @@ -1,14 +1,74 @@ -import Nerv from 'nervjs' +import Nerv, { findDOMNode } from 'nervjs' +import touchable from '../../utils/touchable' +import classnames from 'classnames' +import { isNumber } from '../../utils/index' -class Canvas extends Nerv.Component { +import './style/index.css' + +// canvas-id String canvas 组件的唯一标识符 +// disable-scroll Boolean false 当在 canvas 中移动时且有绑定手势事件时,禁止屏幕滚动以及下拉刷新 +// bindtouchstart EventHandle 手指触摸动作开始 +// bindtouchmove EventHandle 手指触摸后移动 +// bindtouchend EventHandle 手指触摸动作结束 +// bindtouchcancel EventHandle 手指触摸动作被打断,如来电提醒,弹窗 +// bindlongtap EventHandle 手指长按 500ms 之后触发,触发了长按事件后进行移动不会触发屏幕的滚动 +// binderror EventHandle 当发生错误时触发 error 事件,detail = {errMsg: 'something wrong'} + +@touchable() +export default class Canvas extends Nerv.Component { + static defaultProps = { + canvasId: '', + disableScroll: false, + bindError: null + } + state = { + width: null, + height: null + } + getRef = ref => { + const dom = findDOMNode(ref) + this.canvasDom = dom + } + shouldComponentUpdate (nProps, nState) { + if (nState.width !== this.state.width + || nState.height !== this.state.height) { + return true + } + return false + } componentDidMount () { - console.error('H5 暂不支持 Canvas 组件!,请直接用 H5 原生 canvas') + if (!this.canvasDom) return + const { width, height } = this.canvasDom.getBoundingClientRect() + this.setState({ + width, + height + }) } - render () { - const { ...reset } = this.props - return
{this.props.children}
+ const { canvasId, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel, className } = this.props + const { width, height } = this.state + const props = { + canvasId, + onTouchStart, + onTouchMove, + onTouchEnd, + onTouchCancel + } + if (isNumber(width)) { + props.width = width + } + if (isNumber(height)) { + props.height = height + } + return ( +
+ +
+ ) } } - -export default Canvas diff --git a/packages/taro-components/src/components/canvas/style/index.css b/packages/taro-components/src/components/canvas/style/index.css new file mode 100644 index 000000000000..41c077189e7e --- /dev/null +++ b/packages/taro-components/src/components/canvas/style/index.css @@ -0,0 +1,5 @@ +.taro-canvas { + position: relative; + width: 300px; + height: 150px; +} diff --git a/packages/taro-components/src/components/navigator/index.js b/packages/taro-components/src/components/navigator/index.js index 965a589bf5af..47735241be33 100644 --- a/packages/taro-components/src/components/navigator/index.js +++ b/packages/taro-components/src/components/navigator/index.js @@ -2,10 +2,12 @@ import Taro from '@tarojs/taro-h5' import classNames from 'classnames' import Nerv from 'nervjs' -import touchable from '../../utils/touchable' +import hoverable from '../../utils/hoverable' import './navigator.css' +/* eslint-disable prefer-promise-reject-errors */ + /* *target String self 在哪个目标上发生跳转,默认当前小程序,可选值self/miniProgram *url String 当前小程序内的跳转链接 @@ -103,7 +105,7 @@ class Navigator extends Taro.Component { } } -export default touchable({ +export default hoverable({ hoverClass: 'navigator-hover', hoverStopPropergation: false, hoverStartTime: 50, diff --git a/packages/taro-components/src/utils/hoverable.js b/packages/taro-components/src/utils/hoverable.js new file mode 100644 index 000000000000..f5134245486b --- /dev/null +++ b/packages/taro-components/src/utils/hoverable.js @@ -0,0 +1,114 @@ +import Taro from '@tarojs/taro-h5' +import Nerv from 'nervjs' +import omit from 'omit.js' + +/** + * 添加touch能力 + * @param {Object} Options hoverable的默认配置 + * @param {String} [Options.hoverClass] 指定点击时的样式类,当hover-class="none"时,没有点击态效果 + * @param {Boolean} [Options.hoverStopPropergation] 指定是否阻止本节点的祖先节点出现点击态 + * @param {Number} [Options.hoverStartTime] 按住后多久出现点击态,单位毫秒 + * @param {Number} [Options.hoverStayTime] 手指松开后点击态保留时间,单位毫秒 + */ +const hoverable = ({ + hoverClass, + hoverStopPropergation, + hoverStartTime, + hoverStayTime +}) => { + return ComponentClass => { + return class HoverableComponent extends Taro.Component { + static defaultProps = { + hoverClass, + hoverStopPropergation, + hoverStartTime, + hoverStayTime + } + constructor (props, ctx) { + super(props, ctx) + this.state = this.getInitState(this.props) + } + + touchStartTimer = null + touchEndTimer = null + + state = { + isHover: false, + onTouchStart: null, + onTouchEnd: null + } + + getInitState = ({ hoverClass, hoverStartTime, hoverStayTime, hoverStopPropergation, onTouchStart, onTouchEnd }) => { + if (hoverClass === 'none') return + return { + onTouchStart: this.getOnTouchStart({ hoverStartTime, hoverStopPropergation, onTouchStart }), + onTouchEnd: this.getOnTouchEnd({ hoverStayTime, hoverStopPropergation, onTouchEnd }) + } + } + getOnTouchStart = ({ hoverStartTime, hoverStopPropergation, onTouchStart }) => { + return e => { + onTouchStart && onTouchStart(e) + hoverStopPropergation && e.stopPropergation() + this.touchStartTimer && clearTimeout(this.touchStartTimer) + this.touchEndTimer && clearTimeout(this.touchEndTimer) + this.touchStartTimer = setTimeout(() => { + this.setState({ + isHover: true + }) + }, hoverStartTime) + } + } + getOnTouchEnd = ({ hoverStayTime, hoverStopPropergation, onTouchEnd }) => { + return e => { + onTouchEnd && onTouchEnd(e) + hoverStopPropergation && e.stopPropergation() + this.touchStartTimer && clearTimeout(this.touchStartTimer) + this.touchEndTimer && clearTimeout(this.touchEndTimer) + this.touchEndTimer = setTimeout(() => { + this.setState({ + isHover: false + }) + }, hoverStayTime) + } + } + reset = () => { + this.setState({ + isHover: false + }) + } + componentWillMount () { + document.body.addEventListener('touchstart', this.reset) + } + componentWillReceiveProps (nProps, nCtx) { + if ( + nProps.hoverClass !== this.props.hoverClass || + nProps.hoverStopPropergation !== this.props.hoverStopPropergation || + nProps.hoverStartTime !== this.props.hoverStartTime || + nProps.hoverStayTime !== this.props.hoverStayTime + ) { + const stateObj = this.getInitState(nProps) + this.setState(stateObj) + } + } + componentWillUnmount () { + document.body.removeEventListener('touchstart', this.reset) + } + render () { + const { isHover, onTouchStart, onTouchEnd } = this.state + const props = { + ...omit(this.props, [ + 'hoverStopPropergation', + 'hoverStartTime', + 'hoverStayTime' + ]), + isHover, + onTouchStart, + onTouchEnd + } + return + } + } + } +} + +export default hoverable diff --git a/packages/taro-components/src/utils/index.js b/packages/taro-components/src/utils/index.js index a71b6d4a28d8..e3d2416f7805 100755 --- a/packages/taro-components/src/utils/index.js +++ b/packages/taro-components/src/utils/index.js @@ -98,3 +98,7 @@ export const splitUrl = _url => { return res } + +export const isNumber = obj => { + return typeof obj === 'number' +} diff --git a/packages/taro-components/src/utils/touchable.js b/packages/taro-components/src/utils/touchable.js index 62267a87c58b..bcca25075e7b 100644 --- a/packages/taro-components/src/utils/touchable.js +++ b/packages/taro-components/src/utils/touchable.js @@ -1,110 +1,55 @@ import Taro from '@tarojs/taro-h5' -import Nerv from 'nervjs' import omit from 'omit.js' +import Nerv from 'nervjs' -/** - * 添加touch能力 - * @param {Object} Options touchable的默认配置 - * @param {String} [Options.hoverClass] 指定点击时的样式类,当hover-class="none"时,没有点击态效果 - * @param {Boolean} [Options.hoverStopPropergation] 指定是否阻止本节点的祖先节点出现点击态 - * @param {Number} [Options.hoverStartTime] 按住后多久出现点击态,单位毫秒 - * @param {Number} [Options.hoverStayTime] 手指松开后点击态保留时间,单位毫秒 - */ -const touchable = ({ - hoverClass, - hoverStopPropergation, - hoverStartTime, - hoverStayTime +const touchable = (opt = { + longTapTime: 500 }) => { return ComponentClass => { return class TouchableComponent extends Taro.Component { static defaultProps = { - hoverClass, - hoverStopPropergation, - hoverStartTime, - hoverStayTime - } - constructor (props, ctx) { - super(props, ctx) - this.state = this.getInitState(this.props) - } - - touchStartTimer = null - touchEndTimer = null - - state = { - isHover: false, - onTouchStart: null, - onTouchEnd: null + bindTouchStart: null, + bindTouchMove: null, + bindTouchEnd: null, + bindTouchCancel: null, + bindLongTap: null } + timer = null - getInitState = ({ hoverClass, hoverStartTime, hoverStayTime, hoverStopPropergation, onTouchStart, onTouchEnd }) => { - if (hoverClass === 'none') return - return { - onTouchStart: this.getOnTouchStart({ hoverStartTime, hoverStopPropergation, onTouchStart }), - onTouchEnd: this.getOnTouchEnd({ hoverStayTime, hoverStopPropergation, onTouchEnd }) - } - } - getOnTouchStart = ({ hoverStartTime, hoverStopPropergation, onTouchStart }) => { - return e => { - onTouchStart && onTouchStart(e) - hoverStopPropergation && e.stopPropergation() - this.touchStartTimer && clearTimeout(this.touchStartTimer) - this.touchEndTimer && clearTimeout(this.touchEndTimer) - this.touchStartTimer = setTimeout(() => { - this.setState({ - isHover: true - }) - }, hoverStartTime) - } - } - getOnTouchEnd = ({ hoverStayTime, hoverStopPropergation, onTouchEnd }) => { - return e => { - onTouchEnd && onTouchEnd(e) - hoverStopPropergation && e.stopPropergation() - this.touchStartTimer && clearTimeout(this.touchStartTimer) - this.touchEndTimer && clearTimeout(this.touchEndTimer) - this.touchEndTimer = setTimeout(() => { - this.setState({ - isHover: false - }) - }, hoverStayTime) - } - } - reset = () => { - this.setState({ - isHover: false - }) - } - componentWillMount () { - document.body.addEventListener('touchstart', this.reset) - } - componentWillReceiveProps (nProps, nCtx) { - super.componentWillReceiveProps && super.componentWillReceiveProps(nProps, nCtx) - if ( - nProps.hoverClass !== this.props.hoverClass || - nProps.hoverStopPropergation !== this.props.hoverStopPropergation || - nProps.hoverStartTime !== this.props.hoverStartTime || - nProps.hoverStayTime !== this.props.hoverStayTime - ) { - const stateObj = this.getInitState(nProps) - this.setState(stateObj) - } - } - componentWillUnmount () { - document.body.removeEventListener('touchstart', this.reset) + onTouchStart () { + const { bindTouchStart, bindLongTap } = this.props + bindTouchStart && bindTouchStart() + setTimeout(() => { + bindLongTap && bindLongTap() + }, opt.longTapTime) + } + onTouchMove () { + const { bindTouchMove } = this.props + bindTouchMove && bindTouchMove() + } + onTouchEnd () { + this.timer && clearTimeout(this.timer) + const { bindTouchEnd } = this.props + bindTouchEnd && bindTouchEnd() + } + onTouchCancel () { + this.timer && clearTimeout(this.timer) + const { bindTouchCancel } = this.props + bindTouchCancel && bindTouchCancel() } render () { - const { isHover, onTouchStart, onTouchEnd } = this.state const props = { + onTouchStart: this.onTouchStart, + onTouchMove: this.onTouchMove, + onTouchEnd: this.onTouchEnd, + onTouchCancel: this.onTouchCancel, ...omit(this.props, [ - 'hoverStopPropergation', - 'hoverStartTime', - 'hoverStayTime' - ]), - isHover, - onTouchStart, - onTouchEnd + 'bindTouchStart', + 'bindTouchMove', + 'bindTouchEnd', + 'bindTouchCancel', + 'bindLongTap' + ]) } return }