taro3.x: h5-MovableView兼容解决

MovableView不支持h5,使用onTouchMove实现拖拽

main.tsx

import React, { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import {
    View,
    Image,
    Text,
    Label,
    CheckboxGroup,
    Checkbox,
    MovableArea,
    MovableView
} from '@tarojs/components'
import classnames from 'classnames'
import find from 'lodash/find'
import includes from 'lodash/includes'

import api from '@services/api'
import app from '@services/request'
import './index.scss'

interface ISandState {
    value: string
    text: string
    checked: boolean
}

const INIT_SAND_STATE: ISandState[] = [
    {
        value: '1',
        text: '在售',
        checked: true
    },
    {
        value: '2',
        text: '待售',
        checked: true
    },
    {
        value: '3',
        text: '售完',
        checked: true
    }
]

interface IShowState {
    show: boolean
    text: string
}

const INIT_SAND_DATA = {
    sandBuilding: []
}

const INIT_SHOW_STATE = { show: true, text: '收起' }

interface IProps {
    houseId: string,
    outerWidth?: number,
    outerHeight: number,
    currentBuilding?: any,
    setCurrentBuilding: (any) => void,
    updateSandBuilding: (any) => void
}

let lastPointX: number = 0
let lastPointY: number = 0
let imgTop: number = 0
let imgLeft: number = 0
let maxLeft: number = 0
let maxTop: number = 0

const SandCommon = (props: IProps) => {
    const { houseId, outerHeight, currentBuilding = {} } = props
    const [movableView, setMovableView] = useState<any>({})
    const [showState, setShowState] = useState<IShowState>(INIT_SHOW_STATE)
    const [sandState, setSandState] = useState<ISandState[]>(INIT_SAND_STATE)
    const [sandData, setSandData] = useState<any>(INIT_SAND_DATA)
    const [sandBuilding, setSandBuilding] = useState<any>(INIT_SAND_DATA.sandBuilding)
    const [current, setCurrent] = useState<any>({})
    const screenWidth = Taro.getSystemInfoSync().screenWidth
    const outerWidth = props.outerWidth ? props.outerWidth : screenWidth

    useEffect(() => {
        fetchSand()
    }, [houseId])

    useEffect(() => {
        setCurrent(currentBuilding)
    }, [currentBuilding])

    const setImageRealSize = (fang_sand_pic: string) => {
        Taro.getImageInfo({
            src: fang_sand_pic,
            success: (result: any) => {
                setMovableView({
                     result.width,
                    height: result.height,
                    centerX: (outerWidth - result.width) / 2,
                    centerY: (outerHeight - result.height) / 2
                })
            }
        })
    }

    const fetchSand = () => {
        app.request({
            url: app.areaApiUrl(api.getHouseSand),
            data: {
                id: houseId
            }
        }, { loading: false }).then((result: any) => {
            setSandData(result)
            setImageRealSize(result.fang_sand_pic)
            showSandBuilding(INIT_SAND_STATE, result.sandBuilding)
            props.updateSandBuilding(result.sandBuilding)
        })
    }

    const toggleShowState = () => {
        setShowState({
            show: !showState.show,
            text: showState.show ? '展开' : '收起'
        })
    }

    const handleCheckboxChange = (e: any) => {
        const values = e.detail.value
        for (const item of sandState) {
            if (includes(values, item.value)) {
                item.checked = true
            } else {
                item.checked = false
            }
        }
        setSandState(sandState)
        showSandBuilding(sandState, sandData.sandBuilding)
    }

    const showSandBuilding = (sandState, allSandBUilding) => {
        let sandBuilding: any[] = []
        for (const item of allSandBUilding) {
            const target = find(sandState, { value: item.sale_status })
            if (target.checked) {
                sandBuilding.push(item)
            }
        }
        setSandBuilding(sandBuilding)
    }

    const switchCurrent = (item: any) => {
        props.setCurrentBuilding(item)
    }

    const handleTouchStart = (e: any) => {
        const sandView: any = document.getElementsByClassName('sand-view')[0]
        maxLeft = outerWidth - movableView.width
        maxTop = outerHeight - movableView.height
        lastPointX = e.touches[0].clientX;
        lastPointY = e.touches[0].clientY;
        imgLeft = parseFloat(sandView.style.left)
        imgTop = parseFloat(sandView.style.top)
    }

    const handleTouchMove = (e: any) => {
        e.preventDefault();
        let changeX = e.touches[0].clientX - lastPointX;
        let changeY = e.touches[0].clientY - lastPointY;
        let disX = imgLeft + changeX;
        let disY = imgTop + changeY;
        setMovableView({
            ...movableView,
            centerX: Math.max(Math.min(disX, 0), maxLeft),
            centerY: Math.max(Math.min(disY, 0), maxTop)
        })
    }

    const renderSandBuilding = () => {
        return sandBuilding.map((item: any, index: number) => (
            <View
                key={index}
                style={item.style}
                className={classnames('sand-item', `sale-status-${item.sale_status}`, current.id === item.id && 'actived')}
                onClick={() => switchCurrent(item)}
            >
                <Text>{item.name}</Text>
                <Text className="triangle-down"></Text>
            </View>
        ))
    }

    const renderMovableView = () => {
        const { width, height, centerX, centerY } = movableView
        return IS_H5 ?
            (
                <View className="sand-area">
                    <View
                        className="sand-view"
                        style={{
                             `${width}px`,
                            height: `${height}px`,
                            left: `${centerX}px`,
                            top: `${centerY}px`
                        }}
                        onTouchStart={handleTouchStart}
                        onTouchMove={handleTouchMove}
                    >
                        <Image className="taro-image" src={sandData.fang_sand_pic} />
                        {renderSandBuilding()}
                    </View>
                </View>
            ) :
            (
                <MovableArea className="sand-area">
                    <MovableView
                        x={centerX}
                        y={centerY}
                        style={{ width, height }}
                        className="sand-view"
                        direction="all"
                        animation={false}
                    >
                        <Image className="taro-image" src={sandData.fang_sand_pic} />
                        {renderSandBuilding()}
                    </MovableView>
                </MovableArea>
            )
    }

    return (
        <View className="sand-card" style={{  '100%', height: `${outerHeight}px` }}>
            {renderMovableView()}
            <View className="sand-state">
                <CheckboxGroup
                    onChange={handleCheckboxChange}
                    className={classnames('sand-state-box', !showState.show && 'hide')}
                >
                    {
                        sandState.map((item: any, index: any) => (
                            <Label
                                key={index}
                                for={index}
                                className={classnames('check-label', `sale-status-${item.value}`)}
                            >
                                <Checkbox
                                    id={index}
                                    className="check-box"
                                    value={item.value}
                                    checked={item.checked}
                                >
                                </Checkbox>
                                <Text className="check-text">{item.text}</Text>
                            </Label>
                        ))
                    }
                </CheckboxGroup>
                <View className="sand-state-btn" onClick={toggleShowState}>{showState.text}</View>
            </View>
        </View>
    )
}
export default SandCommon
原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/14430960.html