在阵列图的最后一个元素上自动触发单击事件处理程序Reactjs

时间:2017-10-24 07:03:04

标签: javascript jquery arrays reactjs

我在反应渲染中映射数组。有多个DOM渲染。

每个DOM都与click事件处理程序绑定。其中显示了点击的一些细节。

我想触发自动点击该数组的最后一个元素,并将该事件传递给 clickHandler

 let rewardIndicatorView = UIView(frame: CGRect(x: 0, y: 0, width: 3500, height: 120.0))
 rewardIndicatorView.backgroundColor = #colorLiteral(red: 0.08978033811, green: 0.3079419136, blue: 0.8895353675, alpha: 1)


func updateRewardIndicator(nights: UInt) {
// !! Change the values if you want to change offsets !!
let border: CGFloat    = 10.0
let radius: CGFloat    = 50.5
let lineWidth: CGFloat = border


let line = { (frame: CGRect, isDashed: Bool, isEnabled: Bool) -> CAShapeLayer in
    let path = UIBezierPath()
    path.move(to: frame.origin)
    path.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y))

    let layer         = CAShapeLayer()
    layer.path        = path.cgPath
    layer.lineWidth   = frame.size.height
    layer.strokeColor = isEnabled ? #colorLiteral(red: 0.9803921569, green: 0.6823529412, blue: 0.2156862745, alpha: 1).cgColor : #colorLiteral(red: 0.9058823529, green: 0.9058823529, blue: 0.9058823529, alpha: 1).cgColor

    if (isDashed && isEnabled) == true {
        layer.lineDashPattern = [border*2.0 as NSNumber, border*2.0 as NSNumber]
    }
    return layer
}

let circle = { (origin: CGPoint, radius: CGFloat, border: CGFloat, isEnabled: Bool) -> CALayer in
    // Inner circle
    let innerCircleDiameter = max(0, radius - border*2.0) * 2.0
    let outerCircleDiameter = max(0, radius) * 2.0
    let offset = (outerCircleDiameter - innerCircleDiameter + border) / 2.0
    let layer             = CALayer()
    layer.frame           = CGRect(x: origin.x + offset, y: origin.y + offset, width: innerCircleDiameter, height: innerCircleDiameter)
    layer.cornerRadius    = innerCircleDiameter/2.0
    layer.backgroundColor = isEnabled ? #colorLiteral(red: 0.9803921569, green: 0.6823529412, blue: 0.2156862745, alpha: 1).cgColor : #colorLiteral(red: 0.9058823529, green: 0.9058823529, blue: 0.9058823529, alpha: 1).cgColor

    // Border
    guard (0 < border) && (isEnabled == true) else { return layer }
    let shapeLayer         = CAShapeLayer()
    shapeLayer.path        = UIBezierPath(roundedRect: CGRect(x: origin.x + border/2.0, y: origin.y +  border/2.0, width: outerCircleDiameter, height: outerCircleDiameter), cornerRadius: radius).cgPath
    shapeLayer.strokeColor = layer.backgroundColor
    shapeLayer.fillColor   = UIColor.clear.cgColor
    shapeLayer.lineWidth   = border
    shapeLayer.addSublayer(layer)
    return shapeLayer
}


// Accomplished
var distance = (rewardIndicatorView.bounds.size.width - radius*2.0 * CGFloat(RewardInfo.totalNights) - border*2.0) / CGFloat(RewardInfo.totalNights - 1) + radius*2.0
distance = (logIn == true) ? distance : distance + border / CGFloat(RewardInfo.totalNights)

// Circle
let circleLayer = circle(CGPoint(x: 0, y: 0), radius, (logIn ? 0 : border), true)
let accomplishedCircleLayer               = CAReplicatorLayer()
accomplishedCircleLayer.frame             = rewardIndicatorView.bounds
accomplishedCircleLayer.instanceCount     = Int(nights)
accomplishedCircleLayer.preservesDepth    = false
accomplishedCircleLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)



// Animation
if logIn == false {
    /*
     let duration              = 0.5 * CFTimeInterval(nights)
    let fadeAnimation         = CABasicAnimation(keyPath: "opacity")
    fadeAnimation.fromValue   = 1.0
    fadeAnimation.toValue     = 0.0
    fadeAnimation.duration    = duration
    fadeAnimation.repeatCount = Float.greatestFiniteMagnitude

    circleLayer.opacity = 0.0
    circleLayer.add(fadeAnimation, forKey: "FadeAnimation")

    accomplishedCircleLayer.instanceDelay = duration / CFTimeInterval(nights)
     */
}
accomplishedCircleLayer.addSublayer(circleLayer)


// Line
var lineOrigin = CGPoint(x: radius*2.0 + (logIn == true ? 0 : border*3.0), y: (logIn == true ? radius : radius + border/2.0))
var lineDistance = (logIn == true) ? distance - radius*2.0 : distance - radius*2.0 - border*2.0

// Check the count of dash is odd or even. If the count is odd, adjust the border to fit
let dashCount = Int((lineDistance - lineOrigin.x)/border - 1.0)
if logIn == false {
    lineOrigin.x += (dashCount%2 != 0) ? border*2.0 : border
    lineDistance -= (dashCount%2 != 0) ? border*5.0 : border*4.0
}

let accomplishedLineLayer               = CAReplicatorLayer()
accomplishedLineLayer.frame             = rewardIndicatorView.bounds
accomplishedLineLayer.instanceCount     = max(0, Int(nights) - 1)
accomplishedLineLayer.preservesDepth    = false
accomplishedLineLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)
accomplishedLineLayer.addSublayer(line(CGRect(x: lineOrigin.x, y: lineOrigin.y, width: lineDistance, height: lineWidth), !logIn, true))


// Not accompished
// Circle
let notAccomplishedNights = max(0, Int(nights) - 1)
let notAccomplishedCircleRadius = ((logIn == true) ? radius : radius - border/2.0)
let circleOrigin = CGPoint(x: distance * CGFloat(nights) + ((logIn == true) ? 0 : border), y: (logIn == true) ? 0 : border)

let notAccomplishedCircleLayer               = CAReplicatorLayer()
notAccomplishedCircleLayer.frame             = rewardIndicatorView.bounds
notAccomplishedCircleLayer.instanceCount     = Int(RewardInfo.totalNights - nights)
notAccomplishedCircleLayer.preservesDepth    = false
notAccomplishedCircleLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)
notAccomplishedCircleLayer.addSublayer(circle(CGPoint(x: circleOrigin.x, y: circleOrigin.y), notAccomplishedCircleRadius, 0, false))


// Line
lineOrigin.x = distance * CGFloat(notAccomplishedNights) + radius*2.0
let length   = distance - radius*2.0 + ((logIn == true) ? 0 : border)

let notAccomplishedLineLayer               = CAReplicatorLayer()
notAccomplishedLineLayer.frame             = rewardIndicatorView.bounds
notAccomplishedLineLayer.instanceCount     = min(Int(RewardInfo.totalNights - nights), Int(RewardInfo.totalNights - 1))
notAccomplishedLineLayer.preservesDepth    = false
notAccomplishedLineLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)
notAccomplishedLineLayer.addSublayer(line(CGRect(x: lineOrigin.x, y: lineOrigin.y, width: length, height: lineWidth), !logIn, false))

// Add Layers
rewardIndicatorView.layer.addSublayer(notAccomplishedLineLayer)
rewardIndicatorView.layer.addSublayer(notAccomplishedCircleLayer)
rewardIndicatorView.layer.addSublayer(accomplishedLineLayer)
rewardIndicatorView.layer.addSublayer(accomplishedCircleLayer)
}

clickHandler 代码为:

{
    historyData.map((heading, index) => {
        return(
            <div className="history-node-container" key={index}>
              //This is where click handler is being called.
              <div className="history-node" onClick={(e) => {this.handleHistoryClick(e)}}>
                <span className="history-title">{heading.action}</span>
                <input type="hidden" value={heading.comment} className="comment-hidden" />
                <input type="hidden" value={heading.by} className="comment-by-hidden" />
                <input type="hidden" value={heading.role} className="comment-role-hidden" />
                <input type="hidden" value={heading.added_at} className="comment-added-hidden" />
                <span className="history-date">{moment(heading.added_at).format("MMMM Do, YYYY")}</span>
              </div>
            </div>
        )
    })
}

现在我要做的是,如果在映射元素是最后一个我想触发自动点击并相应地显示它的信息。

我将如何实现这一目标?

4 个答案:

答案 0 :(得分:1)

map函数有第三个参数,它是调用map的原始数组。您可以使用它来确定这是否是最后一个。

{
historyData.map((heading, index, array) => {
  if(index===array.length-1){
    //do something
  }
  return(...)

答案 1 :(得分:0)

这可能不是最好的答案,但它可以解决问题

 {
        historyData.map((heading, index,originalArr) => {
            return(
                <div className="history-node-container" key={index}>
                  //This is where click handler is being called.
                  <div className="history-node" onClick={ (index==originalArr.length-1)?this.handleHistoryClick(e) : (e) => {this.handleHistoryClick(e)}}>
                    <span className="history-title">{heading.action}</span>
                    <input type="hidden" value={heading.comment} className="comment-hidden" />
                    <input type="hidden" value={heading.by} className="comment-by-hidden" />
                    <input type="hidden" value={heading.role} className="comment-role-hidden" />
                    <input type="hidden" value={heading.added_at} className="comment-added-hidden" />
                    <span className="history-date">{moment(heading.added_at).format("MMMM Do, YYYY")}</span>
                  </div>
                </div>
            )
        })
    }

这就是诀窍。你想检查当前的itration是否是最后一次迭代。如果它是最后一次。直接调用函数。

onClick={ (index==originalArr.length-1) ? this.handleHistoryClick(e) : (e) => {this.handleHistoryClick(e)}}

答案 2 :(得分:0)

在地图参数中添加数组:

historyData.map(heading, index, array)

并在你的onClick中添加一个条件:

onClick={
 (e) => {
    (index==array.length-1) ? 
       (this.handleHistoryClick(e, true)) : 
       (this.handleHistoryClick(e, false))
  }
}

并在处理程序函数中添加一个条件:

handleHistoryClick(event, isLastElement){
      event.stopPropagation();
      if(isLastElement){
         // do somthing
      }else{
         // do somthing else
      }
}

答案 3 :(得分:0)

除了在render方法中进行渲染之外,不应该做任何事情,特别是像事件触发器之类的东西。 render必须是纯粹的。

说,可以做的是......

  1. 首先将ref存储到变量中的最后一个元素。
  2. 触发componentDidMount中的点击事件。
  3. 示例代码 -

    {
        historyData.map((heading, index) => {
            return(
                <div className="history-node-container" key={index}>
                  // store every item in `this.lastOne`, it will point to the
                  // last item at the end of `map` call.
                  <div className="history-node" ref={item => this.lastOne = item} onClick={(e) => {this.handleHistoryClick(e)}}>
                    <span className="history-title">{heading.action}</span>
                    <input type="hidden" value={heading.comment} className="comment-hidden" />
                    <input type="hidden" value={heading.by} className="comment-by-hidden" />
                    <input type="hidden" value={heading.role} className="comment-role-hidden" />
                    <input type="hidden" value={heading.added_at} className="comment-added-hidden" />
                    <span className="history-date">{moment(heading.added_at).format("MMMM Do, YYYY")}</span>
                  </div>
                </div>
            )
        })
    }
    

    然后在componentDidMount -

    componentDidMount(){
        if (this.lastOne) {
            this.lastOne.click();
        }
    }
    

    如果要在对组件的后续更新中执行单击处理程序,请在componentDidUpdate中添加类似的代码。