事件处理

Taro 元素的事件处理和 DOM 元素的很相似。但是有一点语法上的不同:

Taro 事件绑定属性的命名采用驼峰式写法,而不是小写。如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串 (DOM 元素的写法)。例如,传统的微信小程序模板:

  1. <buttononclick="activateLasers">
  2. Activate Lasers
  3. </button>

Taro 中稍稍有点不同:

  1. <buttononClick={this.activateLasers}>
  2. Activate Lasers
  3. </button>

在 Taro 中另一个不同是你不能使用 catchEvent 的方式阻止事件冒泡。你必须明确的使用 stopPropagation。例如,阻止事件冒泡你可以这样写:

  1. classToggleextendsComponent{
  2. constructor (props){
  3. super(props)
  4. this.state ={isToggleOn:true}
  5. }
  6. onClick =(e)=>{
  7. e.stopPropagation()
  8. this.setState(prevState =>({
  9. isToggleOn:!prevState.isToggleOn
  10. }))
  11. }
  12. render (){
  13. return(
  14. <button onClick={this.onClick}>
  15. {this.state.isToggleOn ?'ON':'OFF'}
  16. </button>
  17. )
  18. }
  19. }

向事件处理程序传递参数

通常我们会为事件处理程序传递额外的参数。例如,传入欲删除行的 id

  1. <buttononClick={this.deleteRow.bind(this,id)}>Delete Row</button>

当你通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面。

  1. classPopperextendsComponent{
  2. constructor (){
  3. super(...arguments)
  4. this.state ={ name:'Hello world!'}
  5. }
  6. // 你可以通过 bind 传入多个参数
  7. preventPop (name, test, e){//事件对象 e 要放在最后
  8. e.stopPropagation()
  9. }
  10. render (){
  11. return<Button onClick={this.preventPop.bind(this,this.state.name,'test')}></Button>
  12. }
  13. }

使用匿名函数

自 v1.2.9 开始支持

注意:在各小程序端,使用匿名函数,尤其是在 循环中 使用匿名函数,比使用 bind 进行事件传参占用更大的内存,速度也会更慢。

除了 bind 之外,事件参数也可以使用匿名函数进行传参。直接写匿名函数不会打乱原有监听函数的参数顺序:

  1. classPopperextendsComponent{
  2. constructor (){
  3. super(...arguments)
  4. this.state ={ name:'Hello world!'}
  5. }
  6. render (){
  7. const name ='test'
  8. return(
  9. <Button onClick={(e)=>{
  10. e.stopPropagation()
  11. this.setState({
  12. name
  13. })
  14. }}>
  15. {this.state.name}
  16. </Button>
  17. )
  18. }
  19. }

注意:使用通过 usingComponents 的第三方组件不支持匿名函数

柯里化

自 v1.3.0-beta.1 开始支持

在各小程序端,使用柯里化 Taro 会在编译后多生成一个匿名函数。

除了 bind 和匿名函数之外,事件参数也可以使用柯里化传参。

  1. classTitleextendsComponent{
  2. handleClick =(index)=>(e)=>{
  3. e.stopPropagation()
  4. this.setState({
  5. currentIndex: index
  6. })
  7. }
  8. render(){
  9. const{ currentIndex }=this.props;
  10. return(
  11. {/* 调用 `this.handleClick(currentIndex)` 会返回一个函数,这个函数可以访问到 `currentIndex` 同时也能满足 `onClick` 的签名 */}
  12. <View onClick={this.handleClick(currentIndex)}>
  13. </View>
  14. )
  15. }
  16. }

注意:使用通过 usingComponents 的第三方组件不支持匿名函数

函数式组件

在函数式组件中,事件传参可以传入事件的引用也可以传入匿名函数,以下是函数式组件配合 useCallback 的一个例子:

  1. constApp=()=>{
  2. const[c1, setC1]= useState(0);
  3. const[c2, setC2]= useState(0);
  4. const[c3, setC3]= useState(0);
  5. const increment = c => c +1
  6. // 只有 useCallback 对应的 c1 或 c2 的值改变时,才会返回新的函数
  7. const increment1 = useCallback(()=> setC1(increment),[c1]);
  8. const increment2 = useCallback(()=> setC2(increment),[c2]);
  9. return(<View>
  10. <Text>Counter1is{c1}</Text>
  11. <Text>Counter2is{c2}</Text>
  12. <Text>Counter3is{c3}</Text>
  13. <View>
  14. <Button onClick={increment1}>IncrementCounter1</Button>
  15. <Button onClick={increment2}>IncrementCounter2</Button>
  16. <Button onClick={()=> setC3(increment)}>IncrementCounter3</Button>
  17. </View>
  18. </View>)
  19. }

任何组件的事件传递都要以 on 开头

在 v1.3.0-beta.0 之后,自定义组件间的事件传递可以不用 on 开头,但内置组件的事件依然是以 on 开头的,为了一致性我们仍然推荐你以 on 开头命名你的事件。

在微信小程序中,可能你会看到像 bindTap 这样的用法,但在 Taro 中,事件参数(props)都以 on 开头:

  1. // 错误
  2. const element =<View bindtap={this.onTag}/>
  3. const element2 =<Input bindfocus={this.onFocus}/>
  4. const element3 =<CustomElement animationEnd={this.props.onAnimationEnd}/>

只要当 JSX 组件传入的参数是函数,参数名就必须以 on 开头:

  1. // 正确
  2. const element =<View onClick={this.onTag}/>
  3. const element2 =<Input onFocus={this.onFocus}/>
  4. const element3 =<CustomElement onAnimationEnd={this.props.onAnimationEnd}/>