序章
Webアプリケーションの構築には、通常、ユーザーとの対話のための準備が含まれます。 ユーザーとの対話を準備する重要な方法の1つは、フォームを使用することです。 ユーザーからさまざまな種類の入力を受け取るために、さまざまなフォームコンポーネントが存在します。 たとえば、パスワードコンポーネントは、ユーザーから機密情報を取得し、それが表示されないようにマスクします。
ほとんどの場合、ユーザーから取得する必要のある情報は boolean-like です。たとえば、yesまたはno、trueまたは false 、enableまたはdisable、onまたはoffなど。 従来、チェックボックスフォームコンポーネントは、これらの種類の入力を取得するために使用されます。 ただし、最近のインターフェイスデザインでは、アクセシビリティの問題がいくつかありますが、チェックボックスの代わりにトグルスイッチが一般的に使用されています。
このチュートリアルでは、Reactを使用してカスタムトグルスイッチコンポーネントを構築する方法を説明します。 チュートリアルの最後に、カスタムトグルスイッチコンポーネントを使用するデモReactアプリがあります。
これは、このチュートリアルで構築する最終的なアプリケーションのデモです。
前提条件
始める前に、次のものが必要です。
-
Node.jsおよびnpmバージョン5.2以降がマシンにインストールされています。 Nodeをインストールしてnpmのバージョンを確認するには、ご使用の環境のNode.jsのインストール方法とローカル開発環境の作成方法ガイドを参照してください。 npm 5.2以降を使用すると、
npx
指図。npx
実行できるようになりますcreate-react-app
パッケージをグローバルにダウンロードせずに。 -
このチュートリアルは、あなたがすでにReactに精通していることを前提としています。 そうでない場合は、 React.js チュートリアルシリーズのコーディング方法を確認するか、Reactドキュメントを読んでReactの詳細を確認してください。
ステップ1—はじめに
開始するには、で新しいReactアプリケーションを作成します npx
と create-react-app
. アプリケーションには任意の名前を付けることができますが、このチュートリアルではreact-toggle-switchを使用します。
- npx create-react-app react-toggle-switch
次に、アプリケーションに必要な依存関係をインストールします。 ターミナルウィンドウを使用して、プロジェクトディレクトリに移動します。
- cd react-toggle-switch
次のコマンドを実行して、必要な依存関係をインストールします。
- npm install bootstrap@4.5.0 lodash@4.17.15 prop-types@15.7.2 classnames@2.2.6 node-sass@4.14.1
注:のバージョンを確認してください node-sass
インストールするインストールは、最小限のサポートのクイックガイドを参照することにより、ご使用の環境と互換性があります。
インストールしました bootstrap
デフォルトのスタイルが必要になるため、アプリケーションの依存関係としてパッケージ化します。 アプリケーションにBootstrapを含めるには、 src/index.js
ファイルを作成し、次の行を他のすべての前に追加します import
声明:
import "bootstrap/dist/css/bootstrap.min.css";
次のコマンドを実行してアプリケーションを起動します。 npm
:
- npm start
アプリケーションを起動すると、開発を開始できます。 ライブリロード機能を備えたブラウザタブが開いていることに注意してください。 ライブリロードは、開発中にアプリケーションへの変更と同期し続けます。
この時点で、アプリケーションビューは次のスクリーンショットのようになります。
次に、トグルコンポーネントを作成します。
ステップ2—作成 ToggleSwitch
成分
コンポーネントを構築する前に、という名前の新しいディレクトリを作成します components
中 src
プロジェクトのディレクトリ。
- mkdir -p src/components
次に、という名前の別の新しいディレクトリを作成します ToggleSwitch
中 components
ディレクトリ。
- mkdir -p src/components/ToggleSwitch
内部に2つの新しいファイルを作成します src/components/ToggleSwitch
、すなわち: index.js
と index.scss
. を作成して開きます index.js
お気に入りのテキストエディタでファイル:
- nano src/components/ToggleSwitch/index.js
次のコンテンツをに追加します src/components/ToggleSwitch/index.js
ファイル:
import PropTypes from 'prop-types';
import classnames from 'classnames';
import isString from 'lodash/isString';
import React, { Component } from 'react';
import isBoolean from 'lodash/isBoolean';
import isFunction from 'lodash/isFunction';
import './index.scss';
class ToggleSwitch extends Component {}
ToggleSwitch.propTypes = {
theme: PropTypes.string,
enabled: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func
]),
onStateChanged: PropTypes.func
}
export default ToggleSwitch;
このコードスニペットでは、 ToggleSwitch
コンポーネントと追加されたタイプは、その小道具のいくつかをチェックします。
theme
:はstring
トグルスイッチのスタイルと色を示します。enabled
:どちらでもかまいませんboolean
またはfunction
それはboolean
、およびレンダリング時のトグルスイッチの状態を決定します。onStateChanged
:は、トグルスイッチの状態が変化したときに呼び出されるコールバック関数です。 これは、スイッチが切り替えられたときに親コンポーネントでアクションをトリガーする場合に役立ちます。
ToggleSwitch状態の初期化
次のコードスニペットでは、の状態を初期化します。 ToggleSwitch
コンポーネントを作成し、トグルスイッチの状態を取得するためのいくつかのコンポーネントメソッドを定義します。
// ...
class ToggleSwitch extends Component {
state = { enabled: this.enabledFromProps() }
isEnabled = () => this.state.enabled
enabledFromProps() {
let { enabled } = this.props;
// If enabled is a function, invoke the function
enabled = isFunction(enabled) ? enabled() : enabled;
// Return enabled if it is a boolean, otherwise false
return isBoolean(enabled) && enabled;
}
}
// ...
ここでは、 enabledFromProps()
メソッドは解決します enabled
渡されて返される小道具 boolean
レンダリング時にスイッチを有効にする必要があるかどうかを示します。 の場合 enabled
小道具は boolean
、ブール値を返します。 それが function
、戻り値が boolean
. それ以外の場合は、 false
.
からの戻り値を使用したことに注意してください enabledFromProps()
イニシャルを設定するには enabled
州。 また、 isEnabled()
現在を取得する方法 enabled
州。
ToggleSwitchの切り替え
先に進んで、クリックされたときにスイッチを切り替えるメソッドを追加しましょう。 次のコードをファイルに追加します。
// ...
class ToggleSwitch extends Component {
// ...other class members here
toggleSwitch = evt => {
evt.persist();
evt.preventDefault();
const { onClick, onStateChanged } = this.props;
this.setState({ enabled: !this.state.enabled }, () => {
const state = this.state;
// Augument the event object with SWITCH_STATE
const switchEvent = Object.assign(evt, { SWITCH_STATE: state });
// Execute the callback functions
isFunction(onClick) && onClick(switchEvent);
isFunction(onStateChanged) && onStateChanged(state);
});
}
}
// ...
このメソッドはとしてトリガーされるため、 click
イベントリスナー、あなたはそれを宣言しました evt
パラメータ。 まず、このメソッドは現在を切り替えます enabled
論理を使用した状態 NOT
(!
)演算子。 状態が更新されると、に渡されるコールバック関数がトリガーされます。 onClick
と onStateChanged
小道具。
以来注意してください onClick
最初の引数としてイベントが必要な場合は、イベントを追加で拡張します SWITCH_STATE
新しい状態オブジェクトを含むプロパティ。 しかし onStateChanged
コールバックは、新しい状態オブジェクトで呼び出されます。
ToggleSwitchのレンダリング
最後に、実装しましょう render()
の方法 ToggleSwitch
成分。 次のコードをファイルに追加します。
// ...
class ToggleSwitch extends Component {
// ...other class members here
render() {
const { enabled } = this.state;
// Isolate special props and store the remaining as restProps
const { enabled: _enabled, theme, onClick, className, onStateChanged, ...restProps } = this.props;
// Use default as a fallback theme if valid theme is not passed
const switchTheme = (theme && isString(theme)) ? theme : 'default';
const switchClasses = classnames(
`switch switch--${switchTheme}`,
className
)
const togglerClasses = classnames(
'switch-toggle',
`switch-toggle--${enabled ? 'on' : 'off'}`
)
return (
<div className={switchClasses} onClick={this.toggleSwitch} {...restProps}>
<div className={togglerClasses}></div>
</div>
)
}
}
// ...
これでたくさんのことが起こっています render()
メソッドなので、少し分解してみましょう。
- まず、
enabled
状態はコンポーネントの状態から分解されます。 - 次に、コンポーネントの小道具を分解し、抽出します
restProps
それはスイッチに渡されます。 これにより、コンポーネントの特別な小道具を傍受して分離することができます。 - 次に、 classnames を使用して、スイッチと内部トグルのクラスを作成します。
theme
そしてそのenabled
コンポーネントの状態。 - 最後に、適切な小道具とクラスを使用してDOM要素をレンダリングします。 渡したことに注意してください
this.toggleSwitch
としてclick
スイッチのイベントリスナー。
ファイルを保存して閉じます。
これで、 ToggleSwitch
.
ステップ3—スタイリング ToggleSwitch
今、あなたは ToggleSwitch
コンポーネントとその必要な機能については、先に進んでそのスタイルを書くことができます。
を開きます index.scss
お気に入りのテキストエディタでファイル:
- nano src/components/ToggleSwitch/index.scss
次のコードスニペットをファイルに追加します。
// DEFAULT COLOR VARIABLES
$ball-color: #ffffff;
$active-color: #62c28e;
$inactive-color: #cccccc;
// DEFAULT SIZING VARIABLES
$switch-size: 32px;
$ball-spacing: 2px;
$stretch-factor: 1.625;
// DEFAULT CLASS VARIABLE
$switch-class: 'switch-toggle';
/* SWITCH MIXIN */
@mixin switch($size: $switch-size, $spacing: $ball-spacing, $stretch: $stretch-factor, $color: $active-color, $class: $switch-class) {}
ここでは、いくつかのデフォルト変数を定義し、 switch
混入します。 次のセクションでは、ミックスインを実装しますが、最初に、 switch
混入します:
$size
:スイッチエレメントの高さ。 長さの単位が必要です。 デフォルトは32px
.$spacing
:丸いボールとスイッチコンテナの間のスペース。 長さの単位が必要です。 デフォルトは2px
.$stretch
:スイッチ要素の幅を伸ばす範囲を決定するために使用される係数。 単位のない数でなければなりません。 デフォルトは1.625
.$color
:アクティブ状態のときのスイッチの色。 これは有効な色の値である必要があります。 この色に関係なく、円形のボールは常に白であることに注意してください。$class
:スイッチを識別するための基本クラス。 これは、スイッチの状態クラスを動的に作成するために使用されます。 デフォルトは'switch-toggle'
. したがって、デフォルトの状態クラスは次のとおりです。.switch-toggle--on
と.switch-toggle--off
.
スイッチミックスインの実装
これがの実装です switch
混入します:
// ...
@mixin switch($size: $switch-size, $spacing: $ball-spacing, $stretch: $stretch-factor, $color: $active-color, $class: $switch-class) {
// SELECTOR VARIABLES
$self: '.' + $class;
$on: #{$self}--on;
$off: #{$self}--off;
// SWITCH VARIABLES
$active-color: $color;
$switch-size: $size;
$ball-spacing: $spacing;
$stretch-factor: $stretch;
$ball-size: $switch-size - ($ball-spacing * 2);
$ball-slide-size: ($switch-size * ($stretch-factor - 1) + $ball-spacing);
// SWITCH STYLES
height: $switch-size;
width: $switch-size * $stretch-factor;
cursor: pointer !important;
user-select: none !important;
position: relative !important;
display: inline-block;
&#{$on},
&#{$off} {
&::before,
&::after {
content: '';
left: 0;
position: absolute !important;
}
&::before {
height: inherit;
width: inherit;
border-radius: $switch-size / 2;
will-change: background;
transition: background .4s .3s ease-out;
}
&::after {
top: $ball-spacing;
height: $ball-size;
width: $ball-size;
border-radius: $ball-size / 2;
background: $ball-color !important;
will-change: transform;
transition: transform .4s ease-out;
}
}
&#{$on} {
&::before {
background: $active-color !important;
}
&::after {
transform: translateX($ball-slide-size);
}
}
&#{$off} {
&::before {
background: $inactive-color !important;
}
&::after {
transform: translateX($ball-spacing);
}
}
}
このミックスインでは、ミックスインに渡されたパラメーターに基づいていくつかの変数を設定することから始めます。 次に、スタイルを作成します。 を使用していることに注意してください ::after
と ::before
スイッチのコンポーネントを動的に作成するための疑似要素。 ::before
スイッチコンテナを作成します ::after
円形のボールを作成します。
また、基本クラスから状態クラスを構築し、それらを変数に割り当てる方法にも注目してください。 The $on
変数は有効な状態のセレクターにマップされますが、 $off
変数は、無効状態のセレクターにマップされます。
また、基本クラス(.switch-toggle
)状態クラスと一緒に使用する必要があります(.switch-toggle--on
また .switch-toggle--off
)利用可能なスタイルの場合。 したがって、あなたは &#{$on}
と &#{$off}
セレクター。
テーマスイッチの作成
今、あなたはあなたを持っています switch
ミックスインでは、トグルスイッチのテーマスタイルを引き続き作成します。 2つのテーマを作成します。 default
と graphite-small
.
次のコードスニペットをに追加します src/components/ToggleSwitch/index.scss
ファイル:
// ...
@function get-switch-class($selector) {
// First parse the selector using `selector-parse`
// Extract the first selector in the first list using `nth` twice
// Extract the first simple selector using `simple-selectors` and `nth`
// Extract the class name using `str-slice`
@return str-slice(nth(simple-selectors(nth(nth(selector-parse($selector), 1), 1)), 1), 2);
}
.switch {
$self: &;
$toggle: #{$self}-toggle;
$class: get-switch-class($toggle);
// default theme
&#{$self}--default > #{$toggle} {
// Always pass the $class to the mixin
@include switch($class: $class);
}
// graphite-small theme
&#{$self}--graphite-small > #{$toggle} {
// A smaller switch with a `gray` active color
// Always pass the $class to the mixin
@include switch($color: gray, $size: 20px, $class: $class);
}
}
ここでは、最初にという名前のSass関数を作成します get-switch-class
それはかかります $selector
パラメータとして。 それは実行されます $selector
Sass関数のチェーンを介して、ファーストクラス名を抽出しようとします。 たとえば、次を受け取った場合:
.class-1 .class-2, .class-3 .class-4
、戻りますclass-1
..class-5.class-6 > .class-7.class-8
、戻りますclass-5
.
次に、のスタイルを定義します .switch
クラス。 トグルクラスを動的に設定します .switch-toggle
そしてそれをに割り当てます $toggle
変数。 から返されたクラス名を割り当てることに注意してください get-switch-class()
への関数呼び出し $class
変数。 最後に、 switch
テーマクラスを作成するために必要なパラメータとミックスインします。
テーマスイッチのセレクターの構造は次のようになっていることに注意してください。 &#{$self}--default > #{$toggle}
(デフォルトのテーマを例として使用)。 すべてをまとめると、これは、スタイルを適用するために、要素の階層が次のようになる必要があることを意味します。
<!-- Use the default theme: switch--default -->
<element class="switch switch--default">
<!-- The switch is in enabled state: switch-toggle--on -->
<element class="switch-toggle switch-toggle--on"></element>
</element>
これは、トグルスイッチのテーマがどのように見えるかを示すデモです。
ステップ4—サンプルアプリを構築する
今、あなたは ToggleSwitch
コンポーネントを必要なスタイルで反応させて、チュートリアルの最初に見たサンプルアプリの作成を始めましょう。
を変更します src/App.js
次のコードスニペットのように見えるファイル:
import classnames from 'classnames';
import snakeCase from 'lodash/snakeCase';
import React, { Component } from 'react';
import Switch from './components/ToggleSwitch';
import './App.css';
// List of activities that can trigger notifications
const ACTIVITIES = [
'News Feeds', 'Likes and Comments', 'Live Stream', 'Upcoming Events',
'Friend Requests', 'Nearby Friends', 'Birthdays', 'Account Sign-In'
];
class App extends Component {
// Initialize app state, all activities are enabled by default
state = { enabled: false, only: ACTIVITIES.map(snakeCase) }
toggleNotifications = ({ enabled }) => {
const { only } = this.state;
this.setState({ enabled, only: enabled ? only : ACTIVITIES.map(snakeCase) });
}
render() {
const { enabled } = this.state;
const headingClasses = classnames(
'font-weight-light h2 mb-0 pl-4',
enabled ? 'text-dark' : 'text-secondary'
);
return (
<div className="App position-absolute text-left d-flex justify-content-center align-items-start pt-5 h-100 w-100">
<div className="d-flex flex-wrap mt-5" style={{width: 600}}>
<div className="d-flex p-4 border rounded align-items-center w-100">
<Switch theme="default"
className="d-flex"
enabled={enabled}
onStateChanged={this.toggleNotifications}
/>
<span className={headingClasses}>Notifications</span>
</div>
{/* ... Notification options here ... */}
</div>
</div>
);
}
}
export default App;
ここで初期化します ACTIVITIES
通知をトリガーできる一連のアクティビティで定数。 次に、2つのプロパティを使用してアプリの状態を初期化しました。
enabled
:aboolean
通知が有効かどうかを示します。only
:array
これには、通知をトリガーするために有効になっているすべてのアクティビティが含まれています。
あなたは snakeCase
Lodash のユーティリティを使用して、状態を更新する前にアクティビティをスネークケースに変換します。 したがって、 'News Feeds'
になります 'news_feeds'
.
次に、 toggleNotifications()
通知スイッチから受信した状態に基づいてアプリの状態を更新するメソッド。 これは、に渡されるコールバック関数として使用されます onStateChanged
トグルスイッチの小道具。 アプリを有効にすると、すべてのアクティビティがデフォルトで有効になることに注意してください。 only
状態プロパティには、すべてのアクティビティが入力されます。
最後に、アプリのDOM要素をレンダリングし、通知オプション用のスロットを残しました。これはまもなく追加されます。 この時点で、アプリは次のスクリーンショットのようになります。
次に、先に進んで、このコメントがある行を探します。
{/* ... Notification options here ... */}
通知オプションを表示するには、次のコンテンツに置き換えます。
// ...
{ enabled && (
<div className="w-100 mt-5">
<div className="container-fluid px-0">
<div className="pt-5">
<div className="d-flex justify-content-between align-items-center">
<span className="d-block font-weight-bold text-secondary small">Email Address</span>
<span className="text-secondary small mb-1 d-block">
<small>Provide a valid email address with which to receive notifications.</small>
</span>
</div>
<div className="mt-2">
<input type="text" placeholder="mail@domain.com" className="form-control" style={{ fontSize: 14 }} />
</div>
</div>
<div className="pt-5 mt-4">
<div className="d-flex justify-content-between align-items-center border-bottom pb-2">
<span className="d-block font-weight-bold text-secondary small">Filter Notifications</span>
<span className="text-secondary small mb-1 d-block">
<small>Select the account activities for which to receive notifications.</small>
</span>
</div>
<div className="mt-5">
<div className="row flex-column align-content-start" style={{ maxHeight: 180 }}>
{ this.renderNotifiableActivities() }
</div>
</div>
</div>
</div>
</div>
) }
に電話をかけたことに気付くかもしれません this.renderNotifiableActivities()
アクティビティをレンダリングします。 先に進んで、このメソッドと他の残りのメソッドを実装しましょう。
次のメソッドをに追加します App
成分:
// ...
class App extends Component {
// ...
toggleActivityEnabled = activity => ({ enabled }) => {
let { only } = this.state;
if (enabled && !only.includes(activity)) {
only.push(activity);
return this.setState({ only });
}
if (!enabled && only.includes(activity)) {
only = only.filter(item => item !== activity);
return this.setState({ only });
}
}
renderNotifiableActivities() {
const { only } = this.state;
return ACTIVITIES.map((activity, index) => {
const key = snakeCase(activity);
const enabled = only.includes(key);
const activityClasses = classnames(
'small mb-0 pl-3',
enabled ? 'text-dark' : 'text-secondary'
);
return (
<div key={index} className="col-5 d-flex mb-3">
<Switch theme="graphite-small"
className="d-flex"
enabled={enabled}
onStateChanged={ this.toggleActivityEnabled(key) }
/>
<span className={activityClasses}>{ activity }</span>
</div>
);
})
}
// ...
}
ここでは、 renderNotifiableActivities
方法。 を使用してすべてのアクティビティを繰り返します ACTIVITIES.map()
トグルスイッチでそれぞれをレンダリングします。 トグルスイッチが graphite-small
テーマ。 また、 enabled
にすでに存在するかどうかを確認することにより、各アクティビティの状態 only
状態変数。
最後に、 toggleActivityEnabled
のコールバック関数を提供するために使用されたメソッド onStateChanged
各アクティビティのトグルスイッチの小道具。 アクティビティを引数として渡し、コールバック関数を返すことができるように、高階関数として定義しました。 アクティビティがすでに有効になっているかどうかを確認し、それに応じて状態を更新します。
これで、アプリは次のスクリーンショットのようになります。
最初のスクリーンショットに示されているように有効にするのではなく、デフォルトですべてのアクティビティを無効にしたい場合は、次の変更を加えることができます。 App
成分:
[src/App.js]
// ...
class App extends Component {
// Initialize app state, all activities are disabled by default
state = { enabled: false, only: [] }
toggleNotifications = ({ enabled }) => {
const { only } = this.state;
this.setState({ enabled, only: enabled ? only : [] });
}
}
このステップで、トグルスイッチの作成が完了しました。 次のステップでは、アプリケーションへのアクセシビリティを改善する方法を学びます。
ステップ5—アクセシビリティの懸念に対処する
従来のチェックボックスの代わりにアプリケーションでトグルスイッチを使用すると、特に従来のチェックボックスを好きなようにスタイル設定するのが難しいため、よりすっきりとしたインターフェイスを作成できます。
ただし、チェックボックスの代わりにトグルスイッチを使用すると、ユーザーエージェントがコンポーネントの機能を正しく解釈できない可能性があるため、アクセシビリティの問題が発生します。
トグルスイッチのアクセシビリティを改善し、ユーザーエージェントが役割を正しく理解できるようにするために、いくつかのことができます。 たとえば、次のARIA属性を使用できます。
<switch-element tabindex="0" role="switch" aria-checked="true" aria-labelledby="#label-element"></switch-element>
トグルスイッチでさらに多くのイベントをリッスンして、ユーザーがコンポーネントを操作する方法を増やすこともできます。
結論
このチュートリアルでは、さまざまなテーマをサポートする適切なスタイルでReactアプリケーション用のカスタムトグルスイッチを作成しました。 従来のチェックボックスの代わりに、アプリケーションでそれを使用する方法を検討しました。 さらに、関連するアクセシビリティの懸念と、改善を行うために何ができるかを調査しました。
このチュートリアルの完全なソースコードについては、GitHubのreact-toggle-switch-demoリポジトリを確認してください。 また、CodeSandboxでこのチュートリアルのライブデモを入手することもできます。