teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

コメント (仕様変更) を受けての追記

2020/10/13 02:40

投稿

thyda.eiqau
thyda.eiqau

スコア2982

answer CHANGED
@@ -101,4 +101,152 @@
101
101
  [...document.querySelectorAll('.card')].forEach(card => {
102
102
  assignEvent(card);
103
103
  });
104
+ ```
105
+
106
+ ## Oct 13, 2020 11:40AM - コメント (仕様変更) を受けての追記
107
+ ```html
108
+ <div class="card">
109
+ <a href="#foo" class="stretched-link">
110
+ <img src="https://placehold.jp/250x200.png">
111
+ <div class="card-body">
112
+ <span role="heading" class="card-title">画像タイトル</span>
113
+ <span class="card-author" data-href="#author">著者名:ふかみ</span>
114
+ <span class="card-tag" data-href="#tags">タグ :夜景・ビル・綺麗</span>
115
+ </div>
116
+ </a>
117
+ </div>
118
+ ```
119
+
120
+ ```css
121
+ .card {
122
+ position: relative;
123
+ width: 250px;
124
+ border: 1px solid gray;
125
+ padding: 5px;
126
+ margin: 0 0 100px 0;
127
+ }
128
+ .card a {
129
+ text-decoration: none;
130
+ }
131
+ .card a:active {
132
+ color: rgb(238, 0, 0);
133
+ color: -webkit-link;
134
+ }
135
+ .card-body {
136
+ display: flex;
137
+ flex-direction: column;
138
+ justify-content: flex-start;
139
+ align-items: flex-start;
140
+ }
141
+ .card-body > span {
142
+ line-height: 2;
143
+ }
144
+ .card-body > span[role="heading"] {
145
+ font-size: 1.17em;
146
+ font-weight: bold;
147
+ }
148
+ .card-body > span:hover {
149
+ text-decoration: underline;
150
+ }
151
+ .card-body > span.clicking {
152
+ color: rgb(238, 0, 0);
153
+ color: -webkit-activelink;
154
+ }
155
+ ```
156
+
157
+ ```js
158
+ const threshold = 150; // ms
159
+
160
+ /**
161
+ * .card-body > [data-href] の要素にマウスが乗ったときに、ベースとなるaタグのhref属性値を書き換える
162
+ * @param Element baseAnchor ベースとなるaタグ
163
+ * @param String customHref リンク先
164
+ */
165
+ const onMouseOverCustomLinkElement = (baseAnchor, customHref) => {
166
+ baseAnchor.dataset.originalHref = baseAnchor.href;
167
+ baseAnchor.href = customHref;
168
+ };
169
+
170
+ /**
171
+ * .card-body > [data-href] の要素からマウスが外れたときに、ベースとなるaタグのhref属性値を元に戻す
172
+ * @param Element baseAnchor ベースとなるaタグ
173
+ */
174
+ const onMouseOutCustomLinkElement = baseAnchor => {
175
+ baseAnchor.href = baseAnchor.dataset.originalHref;
176
+ delete baseAnchor.dataset.originalHref;
177
+ };
178
+
179
+ /**
180
+ * .card-body > span の要素がクリックされたときに、aタグがクリックされたときと同様の色になるようにする
181
+ * @param Element customLinkSpan .card-body > span の要素
182
+ */
183
+ const onMouseDownCustomLinkElement = customLinkSpan => {
184
+ customLinkSpan.classList.add('clicking');
185
+ };
186
+
187
+ /**
188
+ * なんらかの場所でクリック解除されたときに、.card-body > span の要素が、
189
+ * aタグがクリック解除されたときと同様の色になるようにする
190
+ */
191
+ const onMouseUpDocumentBody = () => {
192
+ [...document.querySelectorAll('.card-body > span')].forEach(span => span.classList.remove('clicking'));
193
+ };
194
+
195
+ /**
196
+ * card の中でクリックされたとき、通常のクリックかそうでないか
197
+ * (ロングタップやドラッグ) を判定するために、クリック開始時刻を保持する
198
+ * @param Element card
199
+ */
200
+ const onMouseDownCard = card => {
201
+ card.dataset.clickBegan = (new Date()).getTime();
202
+ };
203
+
204
+ /**
205
+ * card の中でクリック解除されたとき、通常のクリックでないならリンク先への遷移を止める
206
+ * @param Element card
207
+ */
208
+ const onClickCard = (card, evt) => {
209
+ // mouseup した時間が mousedown の thresholdミリ秒以内なら、クリックとみなす
210
+ const clickedMilliseconds = (new Date()).getTime() - card.dataset.clickBegan;
211
+ const isClick = clickedMilliseconds < threshold;
212
+ if(!isClick) {
213
+ evt.preventDefault();
214
+ console.log('prevented');
215
+ }
216
+ };
217
+
218
+ const assignEvent = card => {
219
+ // eventの順番は mousedown > mouseup > click
220
+
221
+ // リンク先を変化させるイベントを登録
222
+ [...card.querySelectorAll('.card-body > [data-href]')].forEach(span => {
223
+ const a = card.querySelector(':scope > a');
224
+ span.addEventListener('mouseover', () => {
225
+ onMouseOverCustomLinkElement(a, span.dataset.href);
226
+ });
227
+ span.addEventListener('mouseout', () => {
228
+ onMouseOutCustomLinkElement(a);
229
+ });
230
+ });
231
+
232
+ // .card-body > span にリンクのようなスタイルを適用するイベントを登録
233
+ [...card.querySelectorAll('.card-body > *')].forEach(span => {
234
+ span.addEventListener('mousedown', () => {
235
+ onMouseDownCustomLinkElement(span);
236
+ });
237
+ });
238
+
239
+ // カード全体のクリック関連イベントを登録
240
+ card.addEventListener('mousedown', () => {
241
+ onMouseDownCard(card);
242
+ });
243
+ card.addEventListener('click', evt => {
244
+ onClickCard(card, evt);
245
+ });
246
+ }
247
+
248
+ [...document.querySelectorAll('.card')].forEach(card => {
249
+ assignEvent(card);
250
+ });
251
+ document.body.addEventListener('mouseup', onMouseUpDocumentBody);
104
252
  ```

1

コメントを受けてJSを修正

2020/10/13 02:40

投稿

thyda.eiqau
thyda.eiqau

スコア2982

answer CHANGED
@@ -59,26 +59,29 @@
59
59
  });
60
60
 
61
61
  card.addEventListener('mouseup', evt => {
62
+ const anchorsParentClass = ['card-title', 'card-author', 'card-tag'];
63
+
62
64
  // mouseup した時間が mousedown の thresholdミリ秒以内なら、クリックとみなす
63
65
  const clickedMilliseconds = (new Date()).getTime() - card.dataset.clickBegan;
64
66
  const isClick = clickedMilliseconds < threshold;
65
67
 
68
+ // 前回の判定のときに保持させていた、クリックを許すかどうかの値を削除する
69
+ [...card.querySelectorAll(`.${anchorsParentClass.join(' > a, .')} > a`)].forEach(link => {
70
+ delete link.dataset.isDisabled;
71
+ });
72
+
66
73
  // cardの中のどの要素が実際クリックされたのかを判定
67
74
  // 動作させたいリンクは .card-title, .card-author, .card-tag のいずれかの子要素
68
- switch(evt.target.parentNode.className) {
75
+ if(anchorsParentClass.indexOf(evt.target.parentNode.className) !== -1) {
69
- case 'card-title':
70
- case 'card-author':
71
- case 'card-tag':
72
- // このリンクを動作させるかどうか保持させる
76
+ // このリンクを動作させるかどうか保持させる
73
- evt.target.dataset.isDisabled = !isClick;
77
+ evt.target.dataset.isDisabled = !isClick;
74
- break;
78
+ return;
79
+ }
75
80
 
76
- default:
77
- // リンク以外の場所でマウスが開放されて、かつクリックとみなす動作だった場合は
81
+ // リンク以外の場所でマウスが開放されて、かつクリックとみなす動作だった場合は
78
- // .card-title > a を発火させる
82
+ // .card-title > a を発火させる
79
- if(isClick) {
83
+ if(isClick) {
80
- card.querySelector('.card-title > a').click();
84
+ card.querySelector('.card-title > a').click();
81
- }
82
85
  }
83
86
  });
84
87