Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@VoQn

タッチモニタもトラックパッドも有るデバイスにおける:hoverの件をDOM属性で解決する

More than 1 year has passed since last update.

前置き

iPadProやMicrosoftSurfaceではタッチモニタでのクリックも、外部ポインタデバイスでのマウスオーバーも両方あるので、単一のコンポーネントに対して「どっちから使われてもいい感じに見えるように」とか言われたりします。
今回はjs側でクラス制御するのでなく、DOM属性を付与するアプローチで、オールドスクールなCSS書きの人と分業できるアプローチを紹介します

要点

  1. 適当な名前の data-* 属性を対象のコンポーネントのDOMに付与する(例えば data-touch)
  2. ontouchstartdata-touch を常にDOMに付ける
  3. onmouseleavedata-touch を常にDOMから剥がす
  4. :not([data-touch]):hover に対して、これまで通りの素朴なCSSを書く
  5. :not([data-touch]):active, [data-touch]:active にポインタクリック時やタップされてる時の状態をCSSで書く

以上

Demo

CodePen: Ignore (:hover) style at Touch device

両方のデバイスを受け付けてるSurfaceや、Chromeのモバイルシミュレーションモードでお試しください

ReactHooksを使った簡易なHOCの例

const TouchableContext = React.createContext({
  isTouch: false,
  handleTouchStart: e => {},
  handleMouseLeave: e => {}
});

const touchable = C => {
  return props => {
    const { onTouchStart, onMouseLeave, ...remain } = props;
    const [isTouch, setTouch] = React.useState(false);
    const handleTouchStart = e => {
      setTouch(true);
      if (onTouchStart) {
        onTouchStart(e);
      }
    };
    const handleMouseLeave = e => {
      setTouch(false);
      if (onMouseLeave) {
        onMouseLeave(e);
      }
    };
    const init = { isTouch, handleTouchStart, handleMouseLeave };
    return (
      <TouchableContext.Provider value={init}>
        <C
          onTouchStart={handleTouchStart}
          onMouseLeave={handleMouseLeave}
          data-touch={isTouch ? "" : null}
          {...remain}
        />
      </TouchableContext.Provider>
    );
  };
};

利用側はほぼ何もしなくてもタッチイベントで data-touch がDOMに付与されるので、コンポーネントの中身の実装に集中できますし、 useContext を使って const { isTouch } = useContext(Touchable); を参照することもできます。

const TextInput = touchable(props => <input type="text" {...props} />);
const Button = touchable(props => <button {...props} />);
2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
VoQn
デジタルプロダクトデザイナー

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?