@dolphinweex/weex-bindingx
Version:
bindingx,expression,binding,weex
448 lines (372 loc) • 12 kB
JavaScript
/** @jsx createElement */
import {createElement, Component, render, findDOMNode} from 'rax';
import View from 'rax-view';
import {isWeex} from '@dolphinweex/universal-env';
import Text from 'rax-text';
import Picture from 'rax-picture';
import bindingx from '../../src/';
function getEl(el) {
return isWeex ? findDOMNode(el).ref : findDOMNode(el);
}
const menuHeight = 500;
const navHeight = 100;
class Menu extends Component {
itemHeight = 100;
rate = 0.2;
duration = 250;
delayOffset = 30;
slideDown() {
let bindingProps = [];
let rate = this.rate;
let duration = this.duration;
const easing = 'easeOutSine';
bindingProps.push({
element: getEl(this.refs.menu),
property: 'height',
expression: `${easing}(t,${navHeight},${menuHeight - navHeight},${duration})`
});
bindingProps.push({
element: getEl(this.refs.close),
property: 'opacity',
expression: `${easing}(t,0,1,${duration})`
});
bindingProps.push({
element: getEl(this.refs.open),
property: 'opacity',
expression: `${easing}(t,1,-1,${duration})`
});
let maxDelay = 0;
for (let i = 0; i < 4; i++) {
let style = getStyle(this.refs[`item_${i}`]);
let destY = i * this.itemHeight + navHeight;
let offset = destY - style.translateY;
let delay = i * this.delayOffset;
maxDelay = Math.max(delay, maxDelay);
bindingProps = bindingProps.concat([
{
config: {
transformOrigin: 'left top'
},
element: getEl(this.refs[`item_${i}`]),
property: 'transform.scale',
expression: `${easing}(t,${rate},1,${duration})`
},
{
element: getEl(this.refs[`item_${i}`]),
property: 'opacity',
expression: `${easing}(t,0,1,${duration})`
},
{
element: getEl(this.refs[`item_${i}`]),
property: 'transform.translateX',
expression: `t>${delay}?${easing}(t-${delay},0,200,${duration}):0`
},
{
element: getEl(this.refs[`item_${i}`]),
property: 'transform.translateY',
expression: `t>${delay}?${easing}(t-${delay},${style.translateY},${offset},${duration}):${style.translateY}`
}
]);
}
bindingx.bind({
eventType: 'timing',
exitExpression: `t>${duration + maxDelay}`,
props: bindingProps
});
}
slideUp = () => {
let bindingProps = [];
let rate = this.rate;
let duration = this.duration;
const easing = 'easeOutSine';
bindingProps.push({
element: getEl(this.refs.menu),
property: 'height',
expression: `${easing}(t,${menuHeight},${navHeight - menuHeight},${duration})`
});
bindingProps.push({
element: getEl(this.refs.close),
property: 'opacity',
expression: `${easing}(t,1,-1,${duration})`
});
bindingProps.push({
element: getEl(this.refs.open),
property: 'opacity',
expression: `${easing}(t,0,1,${duration})`
});
let maxDelay = 0;
for (let i = 0; i < 4; i++) {
let style = getStyle(this.refs[`item_${i}`]);
let destY = i * this.itemHeight * rate;
let offset = destY - style.translateY;
let delay = i * this.delayOffset;
maxDelay = Math.max(delay, maxDelay);
bindingProps = bindingProps.concat([
{
config: {
transformOrigin: 'left top'
},
element: getEl(this.refs[`item_${i}`]),
property: 'transform.scale',
expression: `${easing}(t,1,${rate - 1},${duration})`
},
{
element: getEl(this.refs[`item_${i}`]),
property: 'opacity',
expression: `${easing}(t,1,-1,${duration})`
},
{
element: getEl(this.refs[`item_${i}`]),
property: 'transform.translateX',
expression: `t>${delay}?${easing}(t-${delay},200,-200,${duration}):200`
},
{
element: getEl(this.refs[`item_${i}`]),
property: 'transform.translateY',
expression: `t>${delay}?${easing}(t-${delay},${style.translateY},${offset},${duration}):${style.translateY}`
}
]);
}
bindingx.bind({
eventType: 'timing',
exitExpression: `t>${duration + maxDelay}`,
props: bindingProps
});
}
render() {
let itemHeight = this.itemHeight;
return (<View ref={'menu'} style={{
width: 750,
position: 'absolute',
left: 0,
top: 0,
height: navHeight,
overflow: 'hidden',
backgroundColor: 'rgb(86,57,91)'
}}>
<View style={{flex:1}}>
{['DASHBOARD', 'HISTORY', 'STATISTICS', 'SETTINGS'].map((item, i) => {
return (<View key={i} ref={`item_${i}`}
style={{
position: 'absolute',
left: 0,
top: 0,
opacity: 0,
transform: `translateY(${i * itemHeight + navHeight}rem) translateX(200rem)`,
height: itemHeight,
width: 750
}}>
<Text ref={`txt_${i}`}
style={{
color: 'rgb(234,115,102)',
lineHeight: itemHeight,
fontSize: 32
}}>{item}</Text>
</View>);
})}
<View onClick={this.props.onCloseBtnClick} style={{
position: 'absolute',
left: 0,
top: 0,
width: 100,
height: 100,
alignItems: 'center',
justifyContent: 'center'
}}>
<Picture
ref={'close'}
source={{uri: '//gw.alicdn.com/tfs/TB193sowmtYBeNjSspkXXbU8VXa-64-64.png'}}
style={{width: 60, height: 60, opacity: 0, position: 'absolute', top: 20, left: 20}} />
<Picture
ref={'open'}
source={{uri: '//gw.alicdn.com/tfs/TB1grCUweSSBuNjy0FlXXbBpVXa-64-64.png'}}
style={{width: 60, height: 60, opacity: 1, position: 'absolute', top: 20, left: 20}} />
</View>
</View>
</View>);
}
}
function getTranslateX(el) {
return getStyle(el).translateX;
}
function getTranslateY(el) {
return getStyle(el).translateY;
}
function getStyle(el) {
return bindingx.getComputedStyle(getEl(el));
}
class App extends Component {
componentDidMount() {
}
bindExp = () => {
bindingx.unbindAll();
let translateY1 = getTranslateY(this.refs.block1);
let translateY2 = getTranslateY(this.refs.block2);
let bindingProps = [
{
element: getEl(this.refs.block1),
property: 'transform.translateY',
expression: `max(0,y+${translateY1})`
},
{
element: getEl(this.refs.block2),
property: 'transform.translateY',
expression: `max(0,y-200+${translateY2})`
},
{
element: getEl(this.refs.bar),
property: 'transform.translateY',
expression: `max(0,y-200+${translateY2})`
},
{
element: getEl(this.refs.ball),
property: 'transform.translateY',
expression: `max(0,y-200+${translateY2})`
},
{
element: getEl(this.refs.mask),
property: 'opacity',
expression: `max(0,min(1,(y+${translateY2})/${menuHeight}*0.5))`
}
];
console.log(bindingProps);
bindingx.bind({
anchor: getEl(this.refs.ctn),
eventType: 'pan',
props: bindingProps
}, (e) => {
if (e && e.state === 'end') {
if (e.deltaY > 0) {
this.slideDown();
} else if (e.deltaY < 0) {
this.slideUp();
}
}
});
}
slideDown = () => {
this.isSlideDown = true;
if (this.token) {
bindingx.unbind({
token: this.token,
eventType: 'timing'
});
}
let start1 = getTranslateY(this.refs.block1);
let end1 = menuHeight;
let offset1 = end1 - start1;
let start2 = getTranslateY(this.refs.block2);
let end2 = menuHeight;
let offset2 = end2 - start2;
this.token = bindingx.bind({
eventType: 'timing',
props: [
{
element: getEl(this.refs.block1),
property: 'transform.translateY',
expression: `t>50?easeOutCubic(t-50,${start1},${offset1},350):${start1}`
},
{
element: getEl(this.refs.block2),
property: 'transform.translateY',
expression: `easeOutElastic(t,${start2},${offset2},600)`
},
{
element: getEl(this.refs.ball),
property: 'transform.translateY',
expression: `easeOutElastic(t,${start2},${offset2},600)`
},
{
element: getEl(this.refs.bar),
property: 'transform.translateY',
expression: `easeOutElastic(t,${start2},${offset2},600)`
},
{
element: getEl(this.refs.mask),
property: 'opacity',
expression: 'easeOutCubic(t,0,.5,600)'
},
]
}, (e) => {
if (e && e.state === 'exit') {
}
});
this.refs.menu.slideDown();
}
slideUp = () => {
this.isSlideDown = false;
if (this.token) {
bindingx.unbind({
token: this.token,
eventType: 'timing'
});
}
let style1 = bindingx.getComputedStyle(getEl(this.refs.block1));
let start1 = style1.translateY;
let end1 = 0;
let offset1 = end1 - start1;
let style2 = bindingx.getComputedStyle(getEl(this.refs.block2));
let start2 = style2.translateY;
let end2 = 0;
let offset2 = end2 - start2;
this.token = bindingx.bind({
eventType: 'timing',
props: [
{
element: getEl(this.refs.block1),
property: 'transform.translateY',
expression: `easeOutElastic(t,${start1},${offset1},600)`
},
{
element: getEl(this.refs.block2),
property: 'transform.translateY',
expression: `t>50?easeOutCubic(t-50,${start2},${offset2},${350}):${start2}`
},
{
element: getEl(this.refs.ball),
property: 'transform.translateY',
expression: `t>50?easeOutCubic(t-50,${start2},${offset2},${350}):${start2}`
},
{
element: getEl(this.refs.bar),
property: 'transform.translateY',
expression: `t>50?easeOutCubic(t-50,${start2},${offset2},${350}):${start2}`
},
{
element: getEl(this.refs.mask),
property: 'opacity',
expression: 'easeOutCubic(t,0.5,-0.5,600)'
},
]
});
this.refs.menu.slideUp();
}
toggleSlide = () => {
this.isSlideDown ? this.slideUp() : this.slideDown();
}
render() {
return (<View ref={'ctn'} style={{flex: 1, backgroundColor: 'rgb(86,57,91)', alignItems: 'center'}}
onTouchStart={this.bindExp}>
<View ref={'ball'}
style={{width: 200, height: 200, backgroundColor: 'rgb(234,115,102)', marginTop: 100, borderRadius: 200}} />
<View ref={'bar'} style={{width: 400, height: 40, marginTop: 50, backgroundColor: 'rgb(234,115,102)'}} />
<View style={{width: 750, alignItems: 'flex-start', marginTop: 100,height:800}}>
<View ref={'block1'} style={{width: 750, position: 'absolute', alignItems: 'center'}}>
<View style={{backgroundColor: 'rgb(155,87,124)', width: 700, height: 600, marginTop: 100}} />
</View>
<View ref={'block2'} style={{width: 750, position: 'absolute', alignItems: 'center'}}>
<View style={{
backgroundColor: 'rgb(247,185,128)',
width: 600,
height: 800,
boxShadow: '0rem 10rem 50rem rgba(0,0,0,.5)'
}} />
</View>
</View>
<View ref={'mask'}
style={{backgroundColor: '#000', opacity: 0, position: 'absolute', top: 0, bottom: 0, left: 0, right: 0}} />
<Menu ref={'menu'} onCloseBtnClick={this.toggleSlide} />
</View>);
}
}
render(<App />);