天道酬勤,学无止境

react long press event

Is there a way to add long press event in react-web application?

I have list of addresses. On long press on any address, I want to fire event to delete that address followed by a confirm box.

评论

I've created a codesandbox with a hook to handle long press and click. Basically, on mouse down, touch start events, a timer is created with setTimeout. When the provided time elapses, it triggers long press. On mouse up, mouse leave, touchend, etc, the timer is cleared.

useLongPress.js

import { useCallback, useRef, useState } from "react";

const useLongPress = (
    onLongPress,
    onClick,
    { shouldPreventDefault = true, delay = 300 } = {}
    ) => {
    const [longPressTriggered, setLongPressTriggered] = useState(false);
    const timeout = useRef();
    const target = useRef();

    const start = useCallback(
        event => {
            if (shouldPreventDefault && event.target) {
                    event.target.addEventListener("touchend", preventDefault, {
                    passive: false
                });
                target.current = event.target;
            }
            timeout.current = setTimeout(() => {
                onLongPress(event);
                setLongPressTriggered(true);
            }, delay);
        },
        [onLongPress, delay, shouldPreventDefault]
    );

    const clear = useCallback(
        (event, shouldTriggerClick = true) => {
            timeout.current && clearTimeout(timeout.current);
            shouldTriggerClick && !longPressTriggered && onClick();
            setLongPressTriggered(false);
            if (shouldPreventDefault && target.current) {
                target.current.removeEventListener("touchend", preventDefault);
            }
        },
        [shouldPreventDefault, onClick, longPressTriggered]
    );

    return {
        onMouseDown: e => start(e),
        onTouchStart: e => start(e),
        onMouseUp: e => clear(e),
        onMouseLeave: e => clear(e, false),
        onTouchEnd: e => clear(e)
    };
};

const isTouchEvent = event => {
return "touches" in event;
};

const preventDefault = event => {
if (!isTouchEvent(event)) return;

if (event.touches.length < 2 && event.preventDefault) {
    event.preventDefault();
}
};

export default useLongPress;

To use the hook, App.js

import useLongPress from "./useLongPress";

export default function App() {

    const onLongPress = () => {
        console.log('longpress is triggered');
    };

    const onClick = () => {
        console.log('click is triggered')
    }

    const defaultOptions = {
        shouldPreventDefault: true,
        delay: 500,
    };
    const longPressEvent = useLongPress(onLongPress, onClick, defaultOptions);

    return (
        <div className="App">
            <button {...longPressEvent}>use  Loooong  Press</button>
        </div>
    );
}

Older answer for class components:

You can use MouseDown, MouseUp, TouchStart, TouchEnd events to control timers that can act as a long press event. Check out the code below

class App extends Component {
  constructor() {
    super()
    this.handleButtonPress = this.handleButtonPress.bind(this)
    this.handleButtonRelease = this.handleButtonRelease.bind(this)
  }
  handleButtonPress () {
    this.buttonPressTimer = setTimeout(() => alert('long press activated'), 1500);
  }
  
  handleButtonRelease () {
    clearTimeout(this.buttonPressTimer);
  }

  render() {
    return (
      <div 
          onTouchStart={this.handleButtonPress} 
          onTouchEnd={this.handleButtonRelease} 
          onMouseDown={this.handleButtonPress} 
          onMouseUp={this.handleButtonRelease} 
          onMouseLeave={this.handleButtonRelease}>
        Button
      </div>
    );
  }
}

With hooks in react 16.8 you could rewrite class with functions and hooks.

import { useState, useEffect } from 'react';

export default function useLongPress(callback = () => {}, ms = 300) {
  const [startLongPress, setStartLongPress] = useState(false);

  useEffect(() => {
    let timerId;
    if (startLongPress) {
      timerId = setTimeout(callback, ms);
    } else {
      clearTimeout(timerId);
    }

    return () => {
      clearTimeout(timerId);
    };
  }, [callback, ms, startLongPress]);

  return {
    onMouseDown: () => setStartLongPress(true),
    onMouseUp: () => setStartLongPress(false),
    onMouseLeave: () => setStartLongPress(false),
    onTouchStart: () => setStartLongPress(true),
    onTouchEnd: () => setStartLongPress(false),
  };
}
import useLongPress from './useLongPress';

function MyComponent (props) {
  const backspaceLongPress = useLongPress(props.longPressBackspaceCallback, 500);

  return (
    <Page>
      <Button {...backspaceLongPress}>
        Click me
      </Button>
    </Page>
  );
};

Nice hook! But I would like make a small improvement. Using useCallback to wrap event handlers. This ensures these will not changed on every render.

import { useState, useEffect, useCallback } from 'react';

export default function useLongPress(callback = () => {}, ms = 300) {
  const [startLongPress, setStartLongPress] = useState(false);

  useEffect(() => {
    let timerId;
    if (startLongPress) {
      timerId = setTimeout(callback, ms);
    } else {
      clearTimeout(timerId);
    }

    return () => {
      clearTimeout(timerId);
    };
  }, [callback, ms, startLongPress]);

  const start = useCallback(() => {
    setStartLongPress(true);
  }, []);
  const stop = useCallback(() => {
    setStartLongPress(false);
  }, []);

  return {
    onMouseDown: start,
    onMouseUp: stop,
    onMouseLeave: stop,
    onTouchStart: start,
    onTouchEnd: stop,
  };
}

Based on @Sublime me comment above about avoiding multiple re-renders, my version doesn't use anything that triggers renders:

export function useLongPress({
  onClick = () => {},
  onLongPress = () => {},
  ms = 300,
} = {}) {
  const timerRef = useRef(false);
  const eventRef = useRef({});

  const callback = useCallback(() => {
    onLongPress(eventRef.current);
    eventRef.current = {};
    timerRef.current = false;
  }, [onLongPress]);

  const start = useCallback(
    (ev) => {
      ev.persist();
      eventRef.current = ev;
      timerRef.current = setTimeout(callback, ms);
    },
    [callback, ms]
  );

  const stop = useCallback(
    (ev) => {
      ev.persist();
      eventRef.current = ev;
      if (timerRef.current) {
        clearTimeout(timerRef.current);
        onClick(eventRef.current);
        timerRef.current = false;
        eventRef.current = {};
      }
    },
    [onClick]
  );

  return useMemo(
    () => ({
      onMouseDown: start,
      onMouseUp: stop,
      onMouseLeave: stop,
      onTouchStart: start,
      onTouchEnd: stop,
    }),
    [start, stop]
  );
}

It also provides both onLongPress and onClick and passes on the event object received.

Usage is mostly as described earlier, except arguments are now passed in an object, all are optional:

  const longPressProps = useLongPress({
    onClick: (ev) => console.log('on click', ev.button, ev.shiftKey),
    onLongPress: (ev) => console.log('on long press', ev.button, ev.shiftKey),
  });

// and later:
  return (<button {...longPressProps}>click me</button>);

Here's a component that provides onClick and onHold events - adapt as needed...

CodeSandbox: https://codesandbox.io/s/hold-press-event-r8q9w

Usage:

import React from 'react'
import Holdable from './holdable'

function App() {

  function onClick(evt) {
    alert('click ' + evt.currentTarget.id)
  }

  function onHold(evt) {
    alert('hold ' + evt.currentTarget.id)
  }

  const ids = 'Label1,Label2,Label3'.split(',')

  return (
    <div className="App">
      {ids.map(id => (
        <Holdable
          onClick={onClick}
          onHold={onHold}
          id={id}
          key={id}
        >
          {id}
        </Holdable>
      ))}
    </div>
  )
}

holdable.jsx:

import React from 'react'

const holdTime = 500 // ms
const holdDistance = 3**2 // pixels squared

export default function Holdable({id, onClick, onHold, children}) {

  const [timer, setTimer] = React.useState(null)
  const [pos, setPos] = React.useState([0,0])

  function onPointerDown(evt) {
    setPos([evt.clientX, evt.clientY]) // save position for later
    const event = { ...evt } // convert synthetic event to real object
    const timeoutId = window.setTimeout(timesup.bind(null, event), holdTime)
    setTimer(timeoutId)
  }

  function onPointerUp(evt) {
    if (timer) {
      window.clearTimeout(timer)
      setTimer(null)
      onClick(evt)
    }
  }

  function onPointerMove(evt) {
    // cancel hold operation if moved too much
    if (timer) {
      const d = (evt.clientX - pos[0])**2 + (evt.clientY - pos[1])**2
      if (d > holdDistance) {
        setTimer(null)  
        window.clearTimeout(timer)
      }
    }
  }

  function timesup(evt) {
    setTimer(null)
    onHold(evt)
  }

  return (
    <div
      onPointerDown={onPointerDown}
      onPointerUp={onPointerUp}
      onPointerMove={onPointerMove}
      id={id}
    >
      {children}
    </div>
  )
}

Note: this doesn't work with Safari yet - pointer events are coming in v13 though - https://caniuse.com/#feat=pointer

Here is a Typescript version of the most popular answer, in case it is useful to anybody:

(it also fixes a problem with accessing event properties within the delegated event on the timeOut by using e.persist() and cloning the event)

useLongPress.ts

import { useCallback, useRef, useState } from "react";
  
function preventDefault(e: Event) {
  if ( !isTouchEvent(e) ) return;
  
  if (e.touches.length < 2 && e.preventDefault) {
    e.preventDefault();
  }
};

export function isTouchEvent(e: Event): e is TouchEvent {
  return e && "touches" in e;
};

interface PressHandlers<T> {
  onLongPress: (e: React.MouseEvent<T> | React.TouchEvent<T>) => void,
  onClick?: (e: React.MouseEvent<T> | React.TouchEvent<T>) => void,
}

interface Options {
  delay?: number,
  shouldPreventDefault?: boolean
}

export default function useLongPress<T>(
  { onLongPress, onClick }: PressHandlers<T>,
  { delay = 300, shouldPreventDefault = true }
  : Options
  = {}
) {
  const [longPressTriggered, setLongPressTriggered] = useState(false);
  const timeout = useRef<NodeJS.Timeout>();
  const target = useRef<EventTarget>();

  const start = useCallback(
    (e: React.MouseEvent<T> | React.TouchEvent<T>) => {
      e.persist();
      const clonedEvent = {...e};
      
      if (shouldPreventDefault && e.target) {
        e.target.addEventListener(
          "touchend",
          preventDefault,
          { passive: false }
        );
        target.current = e.target;
      }

      timeout.current = setTimeout(() => {
        onLongPress(clonedEvent);
        setLongPressTriggered(true);
      }, delay);
    },
    [onLongPress, delay, shouldPreventDefault]
  );

  const clear = useCallback((
      e: React.MouseEvent<T> | React.TouchEvent<T>,
      shouldTriggerClick = true
    ) => {
      timeout.current && clearTimeout(timeout.current);
      shouldTriggerClick && !longPressTriggered && onClick?.(e);

      setLongPressTriggered(false);

      if (shouldPreventDefault && target.current) {
        target.current.removeEventListener("touchend", preventDefault);
      }
    },
    [shouldPreventDefault, onClick, longPressTriggered]
  );

  return {
    onMouseDown: (e: React.MouseEvent<T>) => start(e),
    onTouchStart: (e: React.TouchEvent<T>) => start(e),
    onMouseUp: (e: React.MouseEvent<T>) => clear(e),
    onMouseLeave: (e: React.MouseEvent<T>) => clear(e, false),
    onTouchEnd: (e: React.TouchEvent<T>) => clear(e)
  };
};

Brian's solution allows you to pass params to the children which I think is not doable with the Hook. Still, if I may suggest a bit cleaner solution for most common case where you want to add onHold behavior to a single component and you also want to be able to change the onHold timeout.

Material-UI example with Chip component:

'use strict';

const {
  Chip
} = MaterialUI

function ChipHoldable({
  onClick = () => {},
  onHold = () => {},
  hold = 500,
  ...props
}) {
  const [timer, setTimer] = React.useState(null);

  function onPointerDown(evt) {
    const event = { ...evt
    }; // convert synthetic event to real object
    const timeoutId = window.setTimeout(timesup.bind(null, event), hold);
    setTimer(timeoutId);
  }

  function onPointerUp(evt) {
    if (timer) {
      window.clearTimeout(timer);
      setTimer(null);
      onClick(evt);
    }
  }

  const onContextMenu = e => e.preventDefault();

  const preventDefault = e => e.preventDefault(); // so that ripple effect would be triggered

  function timesup(evt) {
    setTimer(null);
    onHold(evt);
  }

  return React.createElement(Chip, {
    onPointerUp,
    onPointerDown,
    onContextMenu,
    onClick: preventDefault,
    ...props
  });
}

const App = () =>  <div> {[1,2,3,4].map(i => < ChipHoldable style={{margin:"10px"}}label = {`chip${i}`}
    onClick = {
      () => console.log(`chip ${i} clicked`)
    }
    onHold = {
      () => console.log(`chip ${i} long pressed`)
    }
    />)}
    </div>


ReactDOM.render( <App/>, document.querySelector('#root'));
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
</head>

<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
  <script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>
</body>

</html>

Ionic React LongPress Example I use it with Ionic React, it works well.

import React, {useState}  from 'react';
import { Route, Redirect } from 'react-router';

interface MainTabsProps { }
const MainTabs: React.FC<MainTabsProps> = () => {

// timeout id  
var initial: any;

// setstate
const [start, setStart] = useState(false);

const handleButtonPress = () => {
  initial = setTimeout(() => {
    setStart(true); // start long button          
    console.log('long press button');
    }, 1500);
}

const handleButtonRelease = () => {
  setStart(false); // stop long press   
  clearTimeout(initial); // clear timeout  
  if(start===false) { // is click
    console.log('click button');
  }  
}

  return (
    <IonPage>
      <IonHeader>
        <IonTitle>Ionic React LongPress</IonTitle>
      </IonHeader>    
      <IonContent className="ion-padding">
        <IonButton expand="block"  
          onMouseDown={handleButtonPress} 
          onMouseUp={handleButtonRelease} >LongPress</IonButton>    
      </IonContent>
    </IonPage>
  );
};

export default MainTabs;

Just wanted to point out that hooks aren't a great solution here since you can't use them in a call back.

for example, if you wanted to add long press to a number of elements:

items.map(item => <button {...useLongPress(() => handle(item))}>{item}</button>)

gets you:

... React Hooks must be called in a React function component or a custom React Hook function

you could however use vanilla JS:

export default function longPressEvents(callback, ms = 500) {
  let timeout = null

  const start = () => timeout = setTimeout(callback, ms)
  const stop = () => timeout && window.clearTimeout(timeout)

  return callback ? {
    onTouchStart: start,
    onTouchMove: stop,
    onTouchEnd: stop,
  } : {}
}

then:

items.map(item => <button { ...longPressEvents(() => handle(item)) }>{item}</button>)

demo: https://codesandbox.io/s/long-press-hook-like-oru24?file=/src/App.js

just be aware that longPressEvents will run every render. Probably not a big deal, but something to keep in mind.

This is the simplest and best solution I could made on my own.

  • This way you don't need to pass the click event
  • Click event still working
  • The hook returns a function instead of the events itselves , then you can use it within a loop or conditionally and pass different callbacks to each element.

useLongPress.js

export default function useLongPress() {
  return function (callback) {
    let timeout;
    let preventClick = false;

    function start() {
      timeout = setTimeout(() => {
        preventClick = true;
        callback();
      }, 300);
    }

    function clear() {
      timeout && clearTimeout(timeout);
      preventClick = false;
    }

    function clickCaptureHandler(e) {
      if (preventClick) {
        e.stopPropagation();
        preventClick = false;
      }
    }

    return {
      onMouseDown: start,
      onTouchStart: start,
      onMouseUp: clear,
      onMouseLeave: clear,
      onTouchMove: clear,
      onTouchEnd: clear,
      onClickCapture: clickCaptureHandler
    };
  }
}

Usage:

import useLongPress from './useLongPress';

export default function MyComponent(){
  const onLongPress = useLongPress();
  const buttons = ['button one', 'button two', 'button three'];

  return (
    buttons.map(text => 
      <button
        onClick={() => console.log('click still working')}
        {...onLongPress(() => console.log('long press worked for ' + text))}
      >
      {text}
      </button>
    )
  )
}

An adaptation of David's solution: a React hook for when you want to repeatedly fire the event. It uses setInterval instead.

export function useHoldPress(callback = () => {}, ms = 300) {
  const [startHoldPress, setStartHoldPress] = useState(false);

  useEffect(() => {
    let timerId;
    if (startHoldPress) {
      timerId = setInterval(callback, ms);
    } else {
      clearTimeout(timerId);
    }

    return () => {
      clearTimeout(timerId);
    };
  }, [startHoldPress]);

  return {
    onMouseDown: () => setStartHoldPress(true),
    onMouseUp: () => setStartHoldPress(false),
    onMouseLeave: () => setStartHoldPress(false),
    onTouchStart: () => setStartHoldPress(true),
    onTouchEnd: () => setStartHoldPress(false)
  };
}

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Trying to catch the Volume onKeyLongPress() not working
    I'm trying to get my app to react to a long key press on volume down with the following code: public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { Log.w("myApp", "LONG PRESS"); } return super.onKeyLongPress(keyCode, event); } However, it only spams a bunch of onKeyPress() events for volume down, and onKeyLongPress() never gets called. My intention is to leave the volume down and up "short" presses alone, and have my app react differently to the volume long press. Can anybody point out what I'm missing?
  • onKeyDown and onKeyLongPress
    I want my application to react differently to a normal and a long pressed Key Event of the Volume Buttons. I've already seen this, but if I keep the volume button pressed, I get a lot of KeyDown Events before I get the KeyLongPressed Event. I'd like to have either one event or the other, not both, so that I can adjust the Volume at a short press and skip a track at a long press. Can you help me out here? This is my code: @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { Log.d("Test", "Long press!"); return true; } return super
  • onKeyDown和onKeyLongPress(onKeyDown and onKeyLongPress)
    问题 我希望我的应用程序对正常和长按的音量按钮的按键事件做出不同的反应。 我已经看到了,但是如果按住音量按钮,则在得到KeyLongPressed事件之前会收到很多KeyDown事件。 我想要一个事件或另一个事件,而不是两个都发生,这样我可以短按一下“音量”,长按一次跳过一个曲目。 你能帮我吗? 这是我的代码: @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { Log.d("Test", "Long press!"); return true; } return super.onKeyLongPress(keyCode, event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { event.startTracking(); Log.d("Test", "Short"); return true; } return super.onKeyDown(keyCode, event); } 任何帮助表示赞赏! -虹膜
  • How to read props from a React Native touchable event currentTarget?
    I have the following React Native code that runs the press() method when a user taps an image. I want to get the itemIndex prop from the event object. I set a break point in the press method and added some expressions to the Watch. From the Watch I determined that the target (event origination) from the event is the Image which is correct. The itemIndex prop is also available. The element being processed is the currentTarget, the Watch sees it's a "RCTView" and I was expecting a TouchableOpacity, so maybe underneath TouchableOpacity is a View? The currentTarget itemIndex prop is undefined, why
  • How to react to keypress events in Go?
    I have a REPL app in Go that should react to keyboard press events (distinct action for each key pressed key) but ReadString expects for return key to be pressed before reading os.Stdin: import ( "bufio" "os" ) for { reader := bufio.NewReader(os.Stdin) key, _ := reader.ReadString('\n') deferKey(key) } How can I react to key press events in Go?
  • Long press definition at XML layout, like android:onClick does
    There is any way to define into XML layout longKeyLongPress definition like onClick does ?. i.e this is my view <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:text="Line 1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/message" android:textSize="15dip" android:textStyle="bold" android:textColor="@color/colorblue" android:shadowDy="1.0" android:shadowDx="1.0" android:shadowRadius="1.0" android:shadowColor="#ffffffff" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="5dip" android
  • 按下后退按钮时如何保持可滚动区域的滚动位置?(How can I retain the scroll position of a scrollable area when pressing back button?)
    问题 我在一个大的可滚动div中有很长的链接列表。 每次用户单击链接然后单击“后退”按钮时,它都从div的最顶部开始。 它对我们的用户不友好。 按下返回按钮时,有什么方法可以让浏览器滚动到先前的位置? 非常感谢你! 回答1 在页面卸载期间,获取滚动位置并将其存储在本地存储中。 然后在页面加载期间,检查本地存储并设置滚动位置。 假设您有一个id为id的div element 。 如果是该页面,请更改选择器:) $(function() { $(window).unload(function() { var scrollPosition = $("div#element").scrollTop(); localStorage.setItem("scrollPosition", scrollPosition); }); if(localStorage.scrollPosition) { $("div#element").scrollTop(localStorage.getItem("scrollPosition")); } }); 回答2 我认为我们应该保存每页的滚动数据,也应该使用会话存储而不是本地存储,因为会话存储只会影响当前选项卡,而本地存储在相同来源的所有选项卡和窗口之间共享 $(function () { var pathName = document.location
  • 将键盘隐藏在react-native中(Hide keyboard in react-native)
    问题 如果我点击一个文本输入,我希望能够点击其他地方以便再次关闭键盘(虽然不是回车键)。 在我阅读的所有教程和博客文章中,我都没有找到与此有关的丝毫信息。 在Simulator中使用本机0.4.2时,此基本示例仍不适用于我。 还无法在我的iPhone上尝试。 <View style={styles.container}> <Text style={styles.welcome}> Welcome to React Native! </Text> <Text style={styles.instructions}> To get started, edit index.ios.js </Text> <Text style={styles.instructions}> Press Cmd+R to reload,{'\n'} Cmd+D or shake for dev menu </Text> <TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1}} onEndEditing={this.clearFocus} /> </View> 回答1 如果您具有keyboardType='numeric' ,则键盘无法关闭的问题会变得更加严重,因为无法消除它。 用ScrollView替换View不是正确的解决方案
  • 如何处理ReactJS中的onKeyPress事件?(How to handle the `onKeyPress` event in ReactJS?)
    问题 如何在onKeyPress事件起作用? 当按下enter (keyCode=13)时,它将enter (keyCode=13)警报。 var Test = React.createClass({ add: function(event){ if(event.keyCode == 13){ alert('Adding....'); } }, render: function(){ return( <div> <input type="text" id="one" onKeyPress={this.add} /> </div> ); } }); React.render(<Test />, document.body); 回答1 我正在使用React 0.14.7,使用onKeyPress和event.key效果很好。 handleKeyPress = (event) => { if(event.key === 'Enter'){ console.log('enter press here! ') } } render: function(){ return( <div> <input type="text" id="one" onKeyPress={this.handleKeyPress} /> </div> ); } 回答2 对我而言, onKeyPress的e
  • 如何检测“ shift + enter”并在Textarea中生成新行?(How do I detect “shift+enter” and generate a new line in Textarea?)
    问题 当前,如果此人在文本区域内按Enter键,则将提交表单。 很好,我想要那个。 但是当他们输入shift + enter时,我希望文本区域移至下一行: \n 如何在JQuery或纯JavaScript中做到尽可能简单? 回答1 更好地使用更简单的解决方案: 我建议使用以下Tim的解决方案更好:https://stackoverflow.com/a/6015906/4031815 我的解决方案 我想你可以做这样的事情。 编辑:更改代码以工作,无论插入位置 代码的第一部分是获得插入符的位置。 参考:如何从头开始以字符为单位,在文本区域中插入符号(而不是像素)的位置? function getCaret(el) { if (el.selectionStart) { return el.selectionStart; } else if (document.selection) { el.focus(); var r = document.selection.createRange(); if (r == null) { return 0; } var re = el.createTextRange(), rc = re.duplicate(); re.moveToBookmark(r.getBookmark()); rc.setEndPoint('EndToStart', re)
  • 推荐的使React组件/ div可拖动的方式(Recommended way of making React component/div draggable)
    问题 我想制作一个可拖动(即可以通过鼠标重定位)的React组件,该组件似乎必然涉及全局状态和分散的事件处理程序。 我可以在JS文件中使用一个全局变量来以肮脏的方式进行操作,甚至可以将其包装在一个不错的闭包接口中,但是我想知道是否有一种方法可以更好地与React结合。 另外,由于我以前从未在原始JavaScript中完成过此任务,所以我想看看专家是如何做到的,以确保我处理了所有极端情况,尤其是与React相关的情况。 谢谢。 回答1 我可能应该把它变成一篇博客文章,但这是一个很可靠的例子。 这些评论应该可以很好地说明问题,但是如果您有任何疑问,请告诉我。 这是玩的小提琴:http://jsfiddle.net/Af9Jt/2/ var Draggable = React.createClass({ getDefaultProps: function () { return { // allow the initial position to be passed in as a prop initialPos: {x: 0, y: 0} } }, getInitialState: function () { return { pos: this.props.initialPos, dragging: false, rel: null // position relative to
  • SendInput() not equal to pressing key manually on keyboard in C++?
    I wanted to write a c++ code to emulate pressing a keyboard key "A": // Set up a generic keyboard event. ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; // hardware scan code for key ip.ki.time = 0; ip.ki.dwExtraInfo = 0; // Press the "..." key ip.ki.wVk = code; // virtual-key code for the "a" key ip.ki.dwFlags = 0; // 0 for key press SendInput(1, &ip, sizeof(INPUT)); // Release the "..." key ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release SendInput(1, &ip, sizeof(INPUT)); It works fine when I launch other program and wait to my program execute, the "A" is clicked and first
  • SendInput()是否等于在C ++中手动按键盘上的键?(SendInput() not equal to pressing key manually on keyboard in C++?)
    问题 我想编写一个c ++代码来模拟按下键盘按键“ A”: // Set up a generic keyboard event. ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; // hardware scan code for key ip.ki.time = 0; ip.ki.dwExtraInfo = 0; // Press the "..." key ip.ki.wVk = code; // virtual-key code for the "a" key ip.ki.dwFlags = 0; // 0 for key press SendInput(1, &ip, sizeof(INPUT)); // Release the "..." key ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release SendInput(1, &ip, sizeof(INPUT)); 当我启动其他程序并等待程序执行时,单击“ A”,然后第一个程序对其做出反应,它就可以正常工作。 但是我发现在另一个应用程序中,我的动作被某种程度上阻止了(我可以手动按下键盘上的“ A”,但是使用我的程序不会引起任何动作)。 因此,我该怎么做才能使从程序中按“ A”与手动按“ A”更加相同
  • “Press and hold” button on Android needs to change states (custom XML selector) using onTouchListener
    I've got a button graphic which needs to have "press and hold" functionality, so instead of using onClickListener, I'm using onTouchListener so that the app can react to MotionEvent.ACTION_DOWN, and MotionEvent.ACTION_UP Depending on how quickly those two events are triggered, I can run a "pressAndHoldHandler" in the time between the two. Anyway, long story short: I have numerous "basic" buttons in the same app that don't require the press and hold functionality, so they are using the onClickListener. Every single one of these buttons have been customized graphically with their own XML
  • 允许“ Enter”键按下提交按钮,而不是仅使用MouseClick(Allowing the “Enter” key to press the submit button, as opposed to only using MouseClick)
    问题 我现在正在学习Swing班及其所有相关内容。 我已经收集了这个玩具程序,该程序会提示您输入名称,然后显示一个JOptionPane消息“您已经输入(您的名字)”。 我使用的“提交”按钮只能单击,但我也想使其与“输入”按钮一起使用。 我尝试按照我正在使用的Java书(Eventful Java,Bruce Danyluk和Murtagh)中的建议添加KeyListener。 这是我的代码: import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; public class NamePrompt extends JFrame{ private static final long serialVersionUID = 1L; String name; public NamePrompt(){ setLayout(new BorderLayout())
  • 使用Android检测长按(Detecting a long press with Android)
    问题 我目前正在使用 onTouchEvent(MotionEvent event){ } 检测用户何时按下我的glSurfaceView,是否有方法检测何时长按。 我猜如果我在开发文档中找不到太多的东西,那将是围绕方法的某种解决方法。 例如注册ACTION_DOWN并查看ACTION_UP之前需要多长时间。 如何使用opengl-es在android上检测长按? 回答1 尝试这个: final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { public void onLongPress(MotionEvent e) { Log.e("", "Longpress detected"); } }); public boolean onTouchEvent(MotionEvent event) { return gestureDetector.onTouchEvent(event); }; 回答2 GestureDetector是最好的解决方案。 这是一个有趣的选择。 在onTouchEvent中,每个ACTION_DOWN计划中都会有一个Runnable在1秒内运行。 在每个ACTION_UP或ACTION_MOVE上
  • 在React Native中获取视图的大小(Get size of a View in React Native)
    问题 是否可以获取某个视图的大小(宽度和高度)? 例如,我有一个视图显示进度: <View ref='progressBar' style={{backgroundColor:'red',flex:this.state.progress}} /> 我需要知道视图的实际宽度才能正确对齐其他视图。 这可能吗? 回答1 从React Native 0.4.2开始,View组件具有onLayout属性。 传递一个接受事件对象的函数。 事件的nativeEvent包含视图的布局。 <View onLayout={(event) => { var {x, y, width, height} = event.nativeEvent.layout; }} /> 每当调整视图大小时,也会调用onLayout处理程序。 主要警告是,在安装组件后一帧会首先调用onLayout处理程序,因此您可能希望隐藏UI,直到计算出布局为止。 回答2 这是唯一对我有用的东西: import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View, Image } from 'react-native'; export default class Comp extends Component { find
  • React Native onPress being called automatically
    I am having trouble with react-native onPress Feature. The onPress should only work when it is actually been triggered by a touch event (i suppose) , that is when i press the button on the screen. But it seems the onPress gets triggered itself when the render function is called. When i try to press manually, it doesn't work. import React, { Component } from 'react'; import { PropTypes, Text, View ,Alert } from 'react-native'; import { Button } from 'react-native-material-design'; export default class Home extends Component { render() { return ( <View style={{flex:1}}> <Button value="Contacts"
  • 是否可以创建一个可以侦听硬件按键操作的Android服务?(Is it possible to create an Android Service that listens for hardware key presses?)
    问题 我想运行一个Android后台服务,该服务将在主屏幕或手机处于睡眠状态时充当按键侦听器。 这可能吗? 从在线的半相关示例中,我整理了以下服务,但收到错误消息:“对于类型Service,未定义onKeyDown”。 这是否意味着如果不重写Launcher便无法完成此操作,或者我显然缺少某些东西? public class ServiceName extends Service { @Override public void onCreate() { //Stuff } public IBinder onBind(Intent intent) { //Stuff return null; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(event.getAction() == KeyEvent.ACTION_DOWN) { switch(keyCode) { case KeyEvent.KEYCODE_A: //Stuff return true; case KeyEvent.KEYCODE_B: //Stuff return true; //etc. } } return super.onKeyDown(keyCode, event); } } 我意识到当您从主屏幕键入内容时
  • Google Maps Places API V3自动完成-在输入时选择第一个选项(Google maps Places API V3 autocomplete - select first option on enter)
    问题 我已经按照http://web.archive.org/web/20120225114154/http://code.google.com:80/intl/sk-SK/apis/在我的输入框中成功实现了Google Maps Places V3自动完成功能。 maps / documentation / javascript / places.html。 它工作得很好,但是当用户按下Enter键时,我很想知道如何从建议中选择第一个选项。 我想我需要一些JS魔术,但是我对JS非常陌生,不知道从哪里开始。 提前致谢! 回答1 在我最近工作的网站上实现自动完成功能时,我遇到了同样的问题。 这是我想出的解决方案: $("input").focusin(function () { $(document).keypress(function (e) { if (e.which == 13) { var firstResult = $(".pac-container .pac-item:first").text(); var geocoder = new google.maps.Geocoder(); geocoder.geocode({"address":firstResult }, function(results, status) { if (status == google