frontendmemo

このサイトは、「html、css、js、ruby,ツールなどについて、自分が覚えたこと、またはいつも忘れて調べることを書き溜め、それが結果といて勉強したての初心者の方や自分と同じような技術レベルの人の助けになることを目的とするWebログ」、略してブログです。挨拶→http://frontendmemo.hatenablog.com/entry/2016/06/25/115845

【css】コンテンツの高さ可変のフッター固定

# フッター固定 css


フッター固定させるのを久しぶりにやってみました。
久しぶりにやると結構めんどくさいことになっていました。

html {
    min-height: 100vh;
    position: relative;
    padding-bottom: 100px; 
}

footer {
    position: absolute;
    bottom: 0;
}

上記padding-bottomはフッターの高さですが固定にすると非常に危険なのでJSでフッターの高さを取得した上で、同じ高さのpadding-bottomを入れる必要があります。

各企業のコーディングガイド(規約)が参考になるのでまとめてみた

各企業のコーディングガイド(規約)が参考になるのでまとめてました。

  • どういうコーディングが正しいんだろ?
  • 自社おコーディング規約を作らなければいけなくなった。

上記に当てはまる人は参考になるかと思います。

特におすすめなのは上から3つ

  • Google
  • Airbnb
  • Chrono Drive

です。

HTML/CSS

Google HTML/CSS Style Guide

qiita.com

抜粋

意味のあるHTMLを書く
目的に応じたHTMLを使用する。(見出しの為のh要素、段落の為のp要素、アンカーの為のa要素など)

実体参照
UTF-8において、—, ”, or ☺などの実体参照を使用する必要はない。
例外としてHTMLで特別な意味を持つ"<"や"&"には使用する。

Airbnb CSS / Sass スタイルガイド

github.com

抜粋

Extend記法
@extend 記法は直感的ではなく、危険な振る舞いを引き起こす可能性があるため、特にネストさせている場合などは使うべきではない。たとえ一番上の階層で仮置きとしてのセレクタを拡張するのだとしても、もしセレクタの順序を後々変更してしまった場合などに問題を引き起こす。(例えば異なるファイルにその記述があり、ファイルのロード順序がずれた場合など) gzipをかければ@extendを使うことによって得られる合理的な出力結果のメリットの大抵はカバーできるし、ミックスインを使えばDRYな素晴らしいコードを生み出すことができる。

もう一度: 決してIDセレクタはネストさせてはいけない!

もしIDセレクタを最初におきたい場合(本来やるべきではないが)、決してネストさせてはいけまない。もしあなた自身がこのようなことをしていると気づいた場合は、もう一度マークアップを見直すかなぜそのような強い詳細度にしなければならなかったのかを確認する必要がある。もしHTMLとCSSを正しいフォーマットで書いていればこのようなことをする必要は絶対にない。

Chrono Drive

html-coding.co.jp

抜粋

調整用Classとは、.mb0 { margin-bottom: 0; }や.taCenter { text-align: center; }のような、単一のプロパティを持つ汎用的なClassのことで、このようなClassの使用は極力避けるべきです。

よくあるのが同じ種類のタグが連続するコンテンツの最後の要素に対して下マージンを消すために.mb0と指定している場合です。
この場合はコンテンツの最後なので.lastChildというクラスを付けた方が適切ですし、Classさえついていれば複数のプロパティを指定でき、他の箇所でも使用できるため汎用性があります。

Qiita(投稿)

qiita.com

抜粋

上記の例では、クラスのみでスタイルを指定したほうが短く記述できます。div .modalのようにdivに制限したクラスを書くと、.modalはdivタグでしか使用できなくなります。.modalの使用が制限されているため、再利用性が低下しています。例のようにdivやpなどタグ指定をすると、 CSS の再利用性が低下するのでタグの指定は避けるようにします。

汎用クラスを使いたがる人
汎用クラスを急に使い出す人がいたらその人は疲れてきた可能性があります。
疲れた人には休暇をとってもらいましょう。

ZOZO

techblog.zozo.com

抜粋

スタイルの再利用性を高めるために、ベース・モジュール・レイアウト・ユーティリティ・ステートという5つの構成要素を定義しています。ベース・モジュール・レイアウト・ステートに関しては、SMACSSと基本の考え方は同一です。ユーティリティはモジュールと類似していますが、スタンドアローンでない点がモジュールと異なります。ユーティリティは規約策定当初モジュールに含まれていました。運用していく中でモジュールの書き方が多様になってきたので、ユーティリティを別に定義しました。

SMART

(若干古め)
rfs.jp

JavaScript

WordPress JavaScript コーディング規約

JavaScript コーディング規約 - WordPress Codex 日本語版

抜粋

オブジェクト
オブジェクト定義は、短い場合には1行で書いても構いません。ただし最大長の制限は忘れないでください。オブジェクト定義が長く1行に収まらない場合は、1行ごとに1つプロパティを定義する形で分割してください。プロパティ名は予約語、または特殊文字を含む場合のみクォートしてください。

// 良い
var map = {
ready: 9,
when: 4,
'you are': 15
};

// 小さなオブジェクトの場合は許される
var map = { ready: 9, when: 4, 'you are': 15 };

// 悪い
var map = { ready: 9,
when: 4, 'you are': 15 };

Node.js Style Guide

github.com

Google JavaScript Style Guide 和訳

cou929.nu

Vue.js

jp.vuejs.org

iosで疑似要素の機種依存テキストに色を付ける方法

疑似要素に機種依存文字を入れる場合iosで確認すると色がつかないので注意が必要です。

例えば下記では疑似要素に✔(チェックマーク)をいれていますが、通常色は黒文字、対策後に色が変わります。


See the Pen
YzKZrdj
by funclur (@funclur)
on CodePen.

本来意味のあるアイコンなので画像にして「チェック」などのaltを入れるほうが適切です。
もしくはiconfontなどの方が機種依存がないので理想です。

ですが、やむを得ない場合など上記の通り機種依存に色をつけたい場合の解決策を解説します。

解決策

解決策は下記になります。

content: '✔\fe0e';

つまり、機種依存文字のあとに\fe0eを入れることで色の変化が可能です。

基本的にアイコンは画像やiconfontを使用し、やむを得ない場合上記のように\fe0eを付けてみてください。

【JavaScript】split、splice、substring使い方まとめ

文字列や配列を成型したいときに用途によってメソッドを使い分けなければなりません。

しかしsplit、splice、substringは名前がsで始まって似ているため覚えずらいです。

用途としては以下です。

  • substring・・・引数を与え指定した範囲を切り出す
  • split・・・指定した文字の前後を配列にする
  • splice・・・配列を引数を使って成型、または切り出し

詳細は以下です。


See the Pen
pozRdYV
by funclur (@funclur)
on CodePen.

【Vue.js 】keyup.enterとblurを同じ要素にいれる方法

# 【Vue.js 】enterとblurを同じ要素に登録しても無限地獄にならない方法


stackoverflowに助けられたので日本語版として残しておきます。

仕様


input要素にフォーカスアウトしたときと、enterキー押したときにアラートを出したい。

実装 (誤り)

<div id="app">
<input type="text" @blur="alert" @keyup.enter=" alert ">
</div>
new Vue({
  el: '#app',
  methods: {
    alert: function() {
      alert()
    }
  }
})

エラー

上記実装だとenterキーを押してalertが表示され、alertを消すときblurが発動しまたalertが表示されます。
この後どういうわけか何度アラートを消してもアラートは表示し続けます。

解決法

解決法は@keyup.enterに $event.target.blur()を入れます。
enterでblurを呼び出すことでアラートの繰り返し防ぎます。

<div id="app">
<input type="text" @blur="alert" @keyup.enter="$event.target.blur()">
</div>


See the Pen
MWgyoQg
by funclur (@funclur)
on CodePen.

【JS】電話番号の文字列からハイフンを追加・削除する

電話番号の文字列からハイフンを追加する

以下が、電話番号の文字列からハイフンを追加するデモです。


See the Pen
ExYPPdd
by funclur (@funclur)
on CodePen.

3と7で決め打ってるところが若干微妙でマジックナンバー化しそうですが、ほかに思いつかなかったのでそうしています。
もし他の桁数の番号でハイフンを入れたい場合は関数化し引数に桁数を付与すれば、汎用性のある機能になります。

電話番号の文字列からハイフンを削除する

削除の場合は簡単で1文字ずつハイフンと比較してハイフンでない場合に配列に入れていけばOKです。


See the Pen
gOYPPqr
by funclur (@funclur)
on CodePen.

【JavaScript】constに一度に複数の変数に値を代入する方法

#コンストに1度に複数の変数に値を代入

コンストに1度に複数の変数に値を代入する方法は以下です。

const { id, hash } = {
  id: 1,
  hash: 2
}
console.log(id)
console.log(hash)


See the Pen
GVOvax
by funclur (@funclur)
on CodePen.

Vue.jsのmodalで背景をクリックで閉じる、複数のモーダルを表示するためには?

公式のmodalは問題あり

公式のmodalは下記のようになっています。


See the Pen
ZEzbaQb
by funclur (@funclur)
on CodePen.

しかしこれだと2点の問題があります。

それは

  • 背景クリックで閉じない
  • 複数のモーダルが作れない

ということです。

そのためこの記事ではVue.jsのモーダルに背景をクリックで閉じる、複数のモーダルが表示できるようにしたいと思います。

背景クリックで閉じる

背景クリックで閉じるようにするためには以下のようにします。

<div class="modal-wrapper" @click="$emit('close')">

背景を表示しているdivに閉じるアクションを追加します。
しかしこれでは、モーダル内のコンテンツをクリックしても閉じてしまうのでモーダル外をクリックしたときのみ閉じるようにしたいです。

<div class="modal-wrapper" @click.self="$emit('close')">

完成したデモは下記です。


See the Pen
dybYZMZ
by funclur (@funclur)
on CodePen.


複数のモーダル

複数のモーダルを作る場合はdataを複数作る必要があります。
こちらもデモにしましたので参照ください。


See the Pen
QWLjeOp
by funclur (@funclur)
on CodePen.

【git bushとyarnが相性悪い?】Error: EBUSY: resource busy or locked, rmdir【解決済み】

git bushをインストールしたところVueでyarn buildができなくなりました。

エラーは下記

Error: EBUSY: resource busy or locked, rmdir 'C:\Users\省略'
error Command failed with exit code 1.

ん~なぞ。git bushをアンインストールしたらbuildできるようになるのでやり方考えないと。

解決策

Windowsでscpを使うならPowerShellでもサーバーアップが可能でした

以下を順に入力

  1. Set-ExecutionPolicy Unrestricted
  2. iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex
  3. choco install openssh
  4. refreshenv

その後以下でアップ可能です。

scp -i 暗号キーのパス アップ対象ファイル アップ先

シャットダウンにしても履歴が↑で出るのでPowerShellいいですね。

【注意】router.jsに記述するrouteの順番

router.jsに記述するrouteの順番は気を付けなければいけません。

下記のようにルーティングすると意図した挙動になりません。

export default new Router({
  mode: 'history',
  routes: [
   {
    {
      path: '/hoge/:id/',
      name: 'fuga2',
      component: () =>
        import(/* webpackChunkName: "takaku" */ './pages/fuga2.vue')
    },
    {
      path: '/hoge/:id/:hash',
      name: 'fuga1',
      component: () =>
        import(/* webpackChunkName: "takaku" */ './pages/fuga1.vue')
    },
  }  
 ]
})


なぜなら/hoge/:id/のようにすると/hoge/:id/:hashというパスもルーティングを通してしまうからです。


そのため順番を下記のように変更します。

export default new Router({
  mode: 'history',
  routes: [
   {
     {
      path: '/hoge/:id/:hash',
      name: 'fuga1',
      component: () =>
        import(/* webpackChunkName: "takaku" */ './pages/fuga1.vue')
    },
    {
      path: '/hoge/:id/',
      name: 'fuga2',
      component: () =>
        import(/* webpackChunkName: "takaku" */ './pages/fuga2.vue')
    },
  }  
 ]
})

ポイントとしては長い記述のパスを優先的に先に書くようにします。

【Vue.js】createdとmountedの違い【簡潔に説明】

Vue.jsのcreatedとmountedの違いはライフサイクルの中で発動タイミングの違いです。

下記を見ていただくとわかりやすいかと思います。


See the Pen
dxZdgK
by funclur (@funclur)
on CodePen.


var app = new Vue({
  el: '#app',
  data: {
  },
  mounted() {
    console.log(2)
  },
  created() {
    console.log(1) 
  }
})
//1
//2

つまり createdのほうが早く、 mountedのほうが遅いです。


詳細に言うとライフサイクルの図の通りとなります。


https://jp.vuejs.org/v2/guide/instance.html

createdの用途

  • windowサイズを取得しての処理
  • Loadingの表示
  • $router文字列の取得
  • 更新時点での分岐処理
  • リダイレクト

mounted

  • Loadingの非表示
  • その他DOM構築後に取得する処理

typescriptの型エラーをなんとかしたい!anyよ、さよなら。エラーの解決法

TypeScriptは型付けできるJSですが、そのエラーの多さに嫌気が指してしまうのは自分だけではないはずです。

この記事ではTypeScriptの何が難しいのか、実際自分がエラーにあたって解決した事例を書いていきます。
尚、勉強中故、正しい情報とは限りませんので他の記事も参考にしつつ最適解を探してみてください。

TypeScript案件の進め方

はじめに1か月TypeScript案件をやってみての感想を進め方をもとに書きます。


型付けしながら実装するわけですが、「どうしても何の型かわからん!」という時は一旦anyにしておくのも手です。

なぜなら、そこに膨大な時間を使うよりまず動くように作れというのがプログラミングにおいては一般的な進め方だと思うからです。
その後、余った時間でじっくり型定義してからでもおそくはありません。


また一箇所で何個もエラーが出るので一つずつanyから変えていくというのも手かと思います。

がんばらないTypeScriptというありがたいお言葉の記事があります。
そこにはanyを使っても問題ないという記述があります。

しかし、型システムをマスターしなければTypeScriptで開発できないわけではありません。複雑な型演算*2は、アプリケーションを書くときに必要になることはほとんどありません。またほかの多くの静的型付き言語と異なり、型エラーで困ったときはいつでもanyで握りつぶせます。動くことが分かっているコードで遭遇する型エラーを握りつぶすのは、特にJavaScriptをTypeScriptに置き換えるフェーズでは、ためらわずにやる方がよいと思っています。

TypeScript再入門「がんばらないTypeScript」で、JavaScriptを“柔らかい”静的型付き言語に(gfx執筆) - エンジニアHub|若手Webエンジニアのキャリアを考える!

しかし、実際それではTypeScriptの意味がなく、最適解がある以上anyを使うことは現場でも容認されないというのが実態かと思いますし自分もそれに賛同しています。

TypeScript型の一覧

TypeScript型の一覧は以下です。

  • number
  • boolean
  • string
  • void(変数としては定義不可)
  • null(同上)
  • undefined(同上)

型定義の何が難しいのか


実践TypeScriptの著者吉井健文さんも本の冒頭で下記のようにおっしゃってます。

「TypeScriptを導入したものの、手間ばかりかかってしまい、結局JavaScriptに戻してしまったという話も少なくありません」


制作現場ではTypeScriptの扱いづらさに混乱をきたしている状態なわけです。


では型定義の何が難しいのでしょう。


自分も実案件に入る前は、const val: number = 1000くらいにしか考えてませんでした。

オブジェクトの型定義の難しさ


objectを型定義しようとしたときobjectにするとエラーになることがあります。


下記はエラーにならない。

const user = {
    val: true,
    key: 1,
    state: {
        login: 'active'
    }
}
function greeter(person: object) {
    return "Hello, " + person;
}
document.body.innerHTML = greeter(user);


しかしAPI呼び出して使用する場合、型定義ファイルをimportで読み込んだ場合エラーになります。


もしかしたらこんなエラーが出るかもしれません。

Element implicitly has an 'any' type because type '{}' has no index signature.

api.ts
export type ApiType = {
  key1: number
   key2: string
  key3: string
}

index.vue
public api: Array<ApiType> = []

上記のようにオブジェクトを配列にする必要があります。

また型をobjectにした場合その中のkeyでエラーが出ることもあるようです。

Property 'name' does not exist on type 'object'
api.key.name

エラーObject is possibly 'undefined'.

上記エラーの場合 undefinedの可能性もあるのにobjectで型定義してしまってるとなります。

Non-null assertion operatorという(!)を末尾に付けることでこのエラーを回避することができます。
意味としては「この変数はundefinedやnullにならない」ことを意味します。

後々型が変更している

後々型が変更した場合ももちろんエラーになります。(そのための型定義)
なので変数定義から道筋をたどって実装するとよさそうです。


以上、TypeScriptで躓いた一部ですが今後も追記していこうと思います。

【Vue.js】location.hrefは使用しません|$routerを使いこなそう

Vue.jsではlocation.hrefの代わりに$routerを使用します。(Vue Routerを使用している場合)

console.log(this.$route)とすると以下のように表示されます。

fullPath: "/hoge"
hash: ""
matched: [{…}]
meta: {}
name: "hoge"
params: {hoge: "1"}
path: "/hoge/huga/1"
query: {}

つまり
console.log(this.$route.name)で

router.jsに指定したnameが取得できます。
location.hrefの場合はthis.$route.fullPathとなります。

prettierで大量のエラーが発生→コマンド一発で解消

コードを自動で成形してくれるprettier便利なのですが、無駄にエラーが発生してストレス感じますね。

大量のエラーが発生することもあるのですが、まるで「バルス」のようにコマンド一発で消すことができたので紹介します。

経緯

VSCODEでprettier拡張機能をinstall、html側で下記のようなエラーが大量発生

Module Warning (from ./node_modules/@vue/cli-plugin-eslint/node_modules/eslint-loader/index.js):
warning: Insert `··` (prettier/prettier) at 

スペースとかタブとか改行などいろいろ試すも変わらず。。

対処法

下記コマンドで解消します。

yarn run lint --fix

そもそもprettier自体、自動でコードを成型してくれるはずなのにエラーなんて出さないで勝手に修正してほしいのですね。
同じような現象が起きた方の救いになれば幸いです。

Vue+TypeScriptで起きたRawLocationエラーの対処法

下記のようなエラーが出ましたが以下の方法で解決しました。

経緯

 error TS2345: Argument of type '{ name: string; query: QueryParams; }' is not assignable to parameter of type 'RawLocation'.
  Type '{ name: string; query: QueryParams; }' is not assignable to type 'Location'.
    Types of property 'query' are incompatible.


Vue+TypeScript案件において他の環境ではエラーが出ないが、自分の環境でtypescriptの上記エラー発生

参考

github.com

上記を参考にvue-routerのバージョンを合わせた

対処法

ターミナルに以下のコマンドをたたけば解消しました。

npm

npm remove vue-router
npm install --save vue-router@3.0.6

npmは試してませんが、おそらくこんな感じかと。。

yarn

yarn upgrade vue-router@3.0.6

typescriptで環境によってエラーの差が出る場合、原因は入れてるモジュールや拡張機能などの開発環境の差があることがほとんどのようですので、そのへんを探ってみるとよいかもしれません。