mp-colorui
Version:
MP ColorUI 是一款基于 Taro 框架并且联合 Color-UI CSS 库开发的多端 UI 组件库(支持小程序端和H5端)
180 lines (178 loc) • 8.4 kB
JavaScript
import Nerv from "nervjs";
import { View } from "@tarojs/components";
import Taro, { createSelectorQuery as _createSelectorQuery, getSystemInfoSync as _getSystemInfoSync } from "@tarojs/taro-h5";
import { classNames, screenPercent } from "../../lib/index";
import ClText from "../text/index";
import ClTip_H5 from "./h5/index";
import "./index.scss";
import { BG_COLOR_LIST } from "../../lib/model";
export default class ClTip extends Taro.Component {
render() {
const props = this.props;
const [showTip, setShowTip] = Taro.useState(props.show);
const [distance, setDistance] = Taro.useState({
top: "auto",
left: "auto",
right: "auto",
bottom: "auto",
transform: "",
arrowTransform: ""
});
const isH5 = Taro.getEnv() === Taro.ENV_TYPE.WEB;
const resver2Zero = params => {
distance.top = "auto";
distance.left = "auto";
distance.right = "auto";
distance.bottom = "auto";
params.forEach(item => {
distance[item.direction] = `${item.long}px`;
});
return distance;
};
Taro.useEffect(() => {
setShowTip(props.show);
}, [props.show]);
Taro.useEffect(() => {
function reRender() {
if (Taro.ENV_TYPE.WEB === Taro.getEnv()) return;
const query = _createSelectorQuery().in(this.$scope);
new Promise(resolve => {
query.select(`#content`).boundingClientRect().exec(res => {
resolve(res[0]);
});
}).then(res => {
query.select("#message").boundingClientRect().exec(data => {
const messageData = data[0];
const contentWidth = props.width || 100;
const screenWidth = 750 * screenPercent;
let customDirection = [];
const systemInfo = _getSystemInfoSync();
const bottomDistance = systemInfo.windowHeight - res.top - res.height;
const leftDistance = screenWidth - res.left - res.width;
const sqrt = Math.sqrt(Math.pow(20 * screenPercent, 2) * 2) / 2;
if (props.direction === "top") {
if (res.top < bottomDistance && res.top < messageData.height) props.direction = "bottom";
customDirection = [{ direction: "bottom", long: 0 }];
console.log(res);
let translateX = (res.width - contentWidth) / 2;
if (res.left < res.right && res.left < screenWidth / 2) {
if (Math.abs(translateX) > res.left) translateX = -res.left;
distance.transform = `translateX(${translateX}px) translateY(-${res.height + 10}px)`;
distance.arrowTransform = `translateX(${Math.abs(translateX) + res.width / 2 - sqrt}px) rotate(45deg) translateY(0)`;
} else {
const maxRight = screenWidth - res.left;
if (maxRight < contentWidth) translateX = contentWidth - maxRight;
distance.transform = `translateX(-${translateX}px) translateY(-${res.height + 10}px)`;
distance.arrowTransform = `translateX(${Math.abs(translateX) + res.width / 2 - sqrt}px) rotate(45deg) translateY(30%)`;
}
} else if (props.direction === "bottom") {
if (res.top > bottomDistance && bottomDistance < messageData.height) props.direction = "bottom";
customDirection = [{ direction: "left", long: 0 }];
let translateX = (res.width - contentWidth) / 2;
if (res.left < res.right && res.left < screenWidth / 2) {
if (Math.abs(translateX) > res.left) translateX = -res.left;
distance.transform = `translateX(${translateX}px) translateY(${res.height + 10}px)`;
distance.arrowTransform = `translateX(${Math.abs(translateX) + res.width / 2 - sqrt}px) rotate(45deg) translateY(0)`;
} else {
const maxRight = screenWidth - res.left;
if (maxRight < contentWidth) translateX = contentWidth - maxRight;
distance.transform = `translateX(-${translateX}px) translateY(${res.height + 10}px)`;
distance.arrowTransform = `translateX(${Math.abs(translateX) + res.width / 2 - sqrt}px) rotate(45deg) translateY(-30%)`;
}
} else if (props.direction === `left`) {
const diffHeight = messageData.height - res.height;
if (res.left < contentWidth + 10 && leftDistance > res.left) props.direction = "right";
customDirection = [{
direction: "right",
long: 0
}];
let moveTop = bottomDistance - (messageData.height / 2 - res.height / 2);
let moveBottom = res.top - (messageData.height / 2 - res.height / 2);
if (moveTop > 0) moveTop = 0;
if (moveBottom > 0) moveBottom = 0;
distance.arrowTransform = `translateY(${messageData.height / 2 - moveTop + moveBottom - sqrt}px) translateX(30%) rotate(45deg)`;
distance.transform = `translateX(${-res.width - 10}px) translateY(${-diffHeight / 2 + moveTop - moveBottom}px)`;
} else if (props.direction === "right") {
if (leftDistance - 10 < contentWidth && leftDistance < res.left) props.direction = "left";
const diffHeight = messageData.height - res.height;
if (res.left < contentWidth + 10) props.direction = "right";
customDirection = [{
direction: "left",
long: 0
}];
let moveTop = bottomDistance - (messageData.height / 2 - res.height / 2);
let moveBottom = res.top - (messageData.height / 2 - res.height / 2);
if (moveTop > 0) moveTop = 0;
if (moveBottom > 0) moveBottom = 0;
distance.arrowTransform = `translateY(${messageData.height / 2 - moveTop + moveBottom - sqrt}px) translateX(-30%) rotate(45deg)`;
distance.transform = `translateX(${res.width + 10}px) translateY(${-diffHeight / 2 + moveTop - moveBottom}px)`;
}
Object.assign(distance, resver2Zero(customDirection));
setDistance(distance);
});
});
}
reRender.call(this);
}, [props.width, props.direction, showTip]);
const ClTip = <View id="content" onClick={() => {
if (props.mode === "click") {
const show = !showTip;
setShowTip(show);
props.onChange && props.onChange(show);
}
}} onTouchStart={() => {
if (props.mode === "touch") {
const show = !showTip;
setShowTip(show);
props.onChange && props.onChange(show);
}
}} onTouchEnd={() => {
if (props.mode === "touch") {
const show = !showTip;
setShowTip(show);
props.onChange && props.onChange(show);
}
}} className={`cl-tip ${showTip ? "cl-tip__showZindex" : ""}`} style={{ position: "relative", display: "inline-block" }}>
<View id="message" className={`cl-tip__content shadow ${showTip ? "show" : "hide"}`} style={{
width: `${showTip ? props.width : 0}px`,
left: distance.left,
right: distance.right,
top: distance.top,
bottom: distance.bottom,
transform: distance.transform
}}>
<View className={`cl-tip__arrow ${props.direction} ${BG_COLOR_LIST[props.bgColor || "white"]} ${showTip ? "showArrow" : "hideArrow"}`} style={{
left: distance.left,
right: distance.right,
top: distance.top,
bottom: distance.bottom,
transform: distance.arrowTransform
}} />
<View className={`cl-tip__message ${BG_COLOR_LIST[props.bgColor || "white"]}`}>
<View style={{ width: `${props.width}px`, padding: "10px" }}>
<ClText text={props.message} />
<View onClick={e => {
e.stopPropagation();
}}>
{this.props.renderMessage}
</View>
</View>
</View>
</View>
{this.props.children}
</View>;
return <View className={classNames(props.className)} style={Object.assign({}, props.style)}>
{isH5 ? <ClTip_H5 {...props} /> : ClTip}
</View>;
}
}
ClTip.defaultProps = {
show: false,
direction: "bottom",
bgColor: "white",
mode: "touch",
width: 150
};
ClTip.options = {
addGlobalClass: true
};