4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue.jsで処理待機中のクルクルが出るボタンを作った

Posted at

こんにちは、猫チーズです。
thumbnail.gif
処理を待機している間クルクルが出るボタンを作る機会があったので、作ったものをここに共有します。
実際に書いたものは単一ファイルコンポーネントですが、今回は初心者もコピペで動作確認しやすいように、npm版のVueを使っています。

流れ

大まかにこのような実行順序です。

  1. ユーザーがボタンを押す
  2. クルクルが表示される
  3. 非同期処理が始まる
  4. 非同期処理が終わる
  5. クルクルが消える

コード

「C」マークのスピナーはCSSのborderなどを駆使して作っています。
スピナー画像を自前で用意したい方は、span.spinnerの部分をimgタグに置き換えてみてください。

以下がコードです(約130行)
index.htmlなどのファイル名で保存すればそのまま動きます。

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>クルクル待機ボタン</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	
	<style>
		/* ボタン */
		.async-button {
			
			/* 見た目など */
			padding: 0.4em 0.8em;
			font-size: inherit;
			background: #36b5b0;
			color: white;
			outline: none;
			border-radius: 6px;
			cursor: pointer;
			
			/* 子要素のスピナーをposition:absolute;にするため */
			position: relative;
			
			/* 文字の位置をpaddingで動かすため */
			transition: padding 0.4s ease;
		}
		
		/* ボタンが待機中のとき */
		.async-button.waiting {
			padding-left: 2em;	/* スピナー分のスペースを空ける */
		}
		
		/* ボタンが押せない状態のとき */
		.async-button:disabled {
			background: gray;
			cursor: not-allowed;
		}
		
		/* スピナー(回転するC) */
		.spinner {
			
			/* 位置 */
			position: absolute;
			left: 0.7em;
			top: 0.6em;
			
			/* スピナーの形を作る */
			display: inline-block;
			width: 0.7em;
			height: 0.7em;
			border: 2px solid;
			border-bottom: 2px solid transparent;
			border-radius: 100%;

			/* アニメーションの指定 */
			animation: spin 1s infinite;
		}

		/* 回転アニメーションの中身 */
		@keyframes spin {
			from { transform: rotateZ(0deg); }
			to { transform: rotateZ(360deg); }
		}
		
		/* スピナーが登場&消えるときの動き */
		.fade-enter-active, .fade-leave-active {
			transition: all .4s;
		}
		.fade-enter, .fade-leave-to {
			left: 0;
			opacity: 0;
		}
	</style>
</head>
<body>
	<div id='app'>
		<async-button @click='do_something' :waiting='doing'>なにかのボタン</async-button>
	</div>

	<script>

		new Vue({
			el: '#app',
			
			data: {
				doing: false,	// 処理実行中か否か
			},

			methods: {
				
				// 何かしらの処理を行う
				do_something() {
					this.doing = true

					// 何秒後かに処理が終了する
					setTimeout(() => {
						this.doing = false
					}, 2000 + Math.random() * 3000)
				},
			},
			
			components: {
				
				// ボタンのコンポーネント
				'async-button': {

					template: `
						<button class='async-button' :class='{waiting}' :disabled='waiting' @click="$emit('click')">
							<transition name='fade'>
								<span class='spinner' v-if='waiting'></span>
							</transition>
							<slot></slot>
						</button>
					`,

					props: {
						// 処理の待機中か否か
						waiting: {
							type: Boolean,
							default: false,
						}
					},
				},
			},
		})
	</script>
</body>
</html>

猫チーズ

高校一年の頃からアプリ作りに没頭していて、今はアプリクリエイターとして生きるために奮闘中です。
今年の4月からサイバーブレイン株式会社でデザイナーを始めました。

Twitter | 猫チーズ
https://twitter.com/miyauchoi

Hello 猫チーズ | 猫チーズと擬似会話ができるブログ
https://blog.miyauchi-akira.app/post/20190927/

ポートフォリオ
https://miyauchi-akira.app

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?