「JavaScript library」の版間の差分

提供:senooken JP Wiki
(JavaScriptからFrameworkを分離。)
 
(Senooken がページ「JavaScript framework」を「JavaScript library」に、リダイレクトを残さずに移動しました: frameworkよりlibraryの方が適切だと感じた。)
 
(同じ利用者による、間の3版が非表示)
1行目: 1行目:
== Grunt ==
=== About ===
JavaScriptのタスクランナー。ビルドやファイルの整形、変換などを行ってくれる。
gruntの他にgulpというのもある。
[https://gruntjs.com/ Grunt: The JavaScript Task Runner]
==== grunt vs. gulp ====
[https://ics.media/entry/3290/ 絶対つまずかないGulp 5入門 - インストールとSassを使うまでの手順 - ICS MEDIA]
設定ファイルが違う。
* grunt: JSONで同期。
* gulp: JavaScriptで非同期。
=== Gruntfile ===
Gruntfile.jsかGruntfile.coffeがタスクの定義ファイル。
以下のコマンドでgruntで実行可能なタスク一覧が表示される。
grunt --help
単にgruntとだけ実行すると、defaultのタスクが実行される。基本はサブコマンドを指定する。
== Node.js ==
=== Install ===
[https://nodejs.org/en/download/package-manager Node.js — Download Node.js®]
ここでプラットフォーム別のインストール方法がある。
Linuxの場合、以下。
# installs nvm (Node Version Manager)
curl -o- <nowiki>https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh</nowiki> | bash
# download and install Node.js (you may need to restart the terminal)
nvm install 22
# verifies the right Node.js version is in the environment
node -v # should print `v22.12.0`
# verifies the right npm version is in the environment
npm -v # should print `10.9.0`
最初の行を実行してインストールしたら~/.bashrcに以下の内容が追記される。即座にインストールを反映したければ現在の端末でも実行する。
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
== jQuery ==
== jQuery ==
[https://api.jquery.com/ jQuery API Documentation]
[https://api.jquery.com/ jQuery API Documentation]
122行目: 167行目:
  <template>
  <template>
  <nowiki> </nowiki> <nowiki><div role="group" class="bv-no-focus-ring">
  <nowiki> </nowiki> <nowiki><div role="group" class="bv-no-focus-ring">
          <div
            <div
            class="form-group-text"
              class="form-group-text"
            :class="{ active: '' + value, 'is-invalid': error }"
              :class="{ active: '' + value, 'is-invalid': error }"
          >
            >
            <b-form-input
              <b-form-input
              :id="'input-text-' + _uid"
                :id="'input-text-' + _uid"
              type="text"
                type="text"
              :formatter="formatter"
                :formatter="formatter"
              :value="value"
                :value="value"
              @input="$emit('input', $event)"
                @input="$emit('input', $event)"
              @compositionend="$emit('input', normalize($event.target.value))"
                @compositionend="$emit('input', normalize($event.target.value))"
              @paste="$emit('input', paste($event))"
                @paste="$emit('input', paste($event))"
            />
              />
            <label :for="'input-text-' + _uid">{{
              <label :for="'input-text-' + _uid">{{
              /[._]/.test(label) ? $t(label) : label
                /[._]/.test(label) ? $t(label) : label
            }}</nowiki><nowiki></label></nowiki>
              }}</nowiki><nowiki></label></nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki>  <nowiki><div :id="'input-live-feedback-' + _uid" class="invalid-feedback">
  <nowiki> </nowiki>  <nowiki><div :id="'input-live-feedback-' + _uid" class="invalid-feedback">
            {{ $t(error) }}</nowiki>
              {{ $t(error) }}</nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki> <nowiki></div></nowiki>
  <nowiki> </nowiki> <nowiki></div></nowiki>
  </template>
  </template>
  <nowiki><script>
  <nowiki><script>
      export default {
        export default {
        props: {
          props: {
          value: { type: String, default: ''</nowiki>, required: true },
            value: { type: String, default: ''</nowiki>, required: true },
  <nowiki> </nowiki>  label: { type: String, default: <nowiki>''</nowiki>, required: true },
  <nowiki> </nowiki>  label: { type: String, default: <nowiki>''</nowiki>, required: true },
  <nowiki> </nowiki>  // ファームウェアとスケジュールにエラーのないフォームがある。
  <nowiki> </nowiki>  // ファームウェアとスケジュールにエラーのないフォームがある。
195行目: 240行目:
  <template>
  <template>
  <nowiki> </nowiki> <nowiki><div role="group" class="bv-no-focus-ring mb-3">
  <nowiki> </nowiki> <nowiki><div role="group" class="bv-no-focus-ring mb-3">
          <div
            <div
            class="form-group-text"
              class="form-group-text"
            :class="{ active: '' + value, 'is-invalid': error }"
              :class="{ active: '' + value, 'is-invalid': error }"
          >
            >
            <b-form-input
              <b-form-input
              :id="'input-number-' + _uid"
                :id="'input-number-' + _uid"
              class="form-control"
                class="form-control"
              type="tel"
                type="tel"
              autocomplete="off"
                autocomplete="off"
              maxlength="10"
                maxlength="10"
              :formatter="formatter"
                :formatter="formatter"
              :value="value"
                :value="value"
              @input="$emit('input', $event)"
                @input="$emit('input', $event)"
              @compositionend="$emit('input', normalize($event.target.value))"
                @compositionend="$emit('input', normalize($event.target.value))"
            />
              />
            <label :for="'input-number-' + _uid">{{ $t(label) }}</nowiki><nowiki></label></nowiki>
              <label :for="'input-number-' + _uid">{{ $t(label) }}</nowiki><nowiki></label></nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki>  <nowiki><div :id="'input-live-feedback-' + _uid" class="invalid-feedback">
  <nowiki> </nowiki>  <nowiki><div :id="'input-live-feedback-' + _uid" class="invalid-feedback">
            {{ $t(error) }}</nowiki>
              {{ $t(error) }}</nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki>  <nowiki></div></nowiki>
  <nowiki> </nowiki> <nowiki></div></nowiki>
  <nowiki> </nowiki> <nowiki></div></nowiki>
  </template>
  </template>
  <nowiki><script>
  <nowiki><script>
      export default {
        export default {
        props: {
          props: {
          value: { type: [String, Number], default: ''</nowiki>, required: true },
            value: { type: [String, Number], default: ''</nowiki>, required: true },
  <nowiki> </nowiki>  error: { type: String, default: <nowiki>''</nowiki>, required: true },
  <nowiki> </nowiki>  error: { type: String, default: <nowiki>''</nowiki>, required: true },
  <nowiki> </nowiki>  label: { type: String, default: <nowiki>''</nowiki>, required: true },
  <nowiki> </nowiki>  label: { type: String, default: <nowiki>''</nowiki>, required: true },
250行目: 295行目:
  <nowiki></script></nowiki>
  <nowiki></script></nowiki>


==== error '<template>' cannot be keyed. Place the key on real elements instead vue/no-template-key ====
[https://stackoverflow.com/questions/56476413/custom-elements-in-iteration-require-v-bindkey-directives vue.js - Custom elements in iteration require 'v-bind:key' directives - Stack Overflow]
==== ハイライト ====
<nowiki>https://forum.vuejs.org/t/highlight-in-html-a-new-object-in-javascript-array/38877/9</nowiki>
nextTickでやればいいか。
[https://sagatto.com/20181031_highlight_display_at_vue_js 【Vue.js】検索文字などの特定文字を、マーカーでハイライト表示するコンポーネントを作った | SAGA.TXT]
検索キーワードで検索対象をsplitして、key/value形式で順番に配列で配置する。
==== カスタムコンポーネントのv-bind ====
[https://stackoverflow.com/questions/42918710/how-to-use-v-bind-in-a-custom-component javascript - How to use v-bind in a custom component? - Stack Overflow]
[https://github.com/buefy/buefy/issues/1038 using v-model b-input component · Issue #1038 · buefy/buefy]
[[Category:JavaScript]]
[[Category:JavaScript]]

2024年12月20日 (金) 17:50時点における最新版

Grunt

About

JavaScriptのタスクランナー。ビルドやファイルの整形、変換などを行ってくれる。

gruntの他にgulpというのもある。

Grunt: The JavaScript Task Runner

grunt vs. gulp

絶対つまずかないGulp 5入門 - インストールとSassを使うまでの手順 - ICS MEDIA

設定ファイルが違う。

  • grunt: JSONで同期。
  • gulp: JavaScriptで非同期。

Gruntfile

Gruntfile.jsかGruntfile.coffeがタスクの定義ファイル。

以下のコマンドでgruntで実行可能なタスク一覧が表示される。

grunt --help

単にgruntとだけ実行すると、defaultのタスクが実行される。基本はサブコマンドを指定する。

Node.js

Install

Node.js — Download Node.js®

ここでプラットフォーム別のインストール方法がある。

Linuxの場合、以下。

# installs nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
# download and install Node.js (you may need to restart the terminal)
nvm install 22
# verifies the right Node.js version is in the environment
node -v # should print `v22.12.0`
# verifies the right npm version is in the environment
npm -v # should print `10.9.0`

最初の行を実行してインストールしたら~/.bashrcに以下の内容が追記される。即座にインストールを反映したければ現在の端末でも実行する。

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

jQuery

jQuery API Documentation

レガシー

jQueryがもういらなくなってきたという意見がある。

  • Webブラウザー間の違いがなくなってきた。
  • 標準のJavaScriptでできることが増えた。

上記2点が大きい。jQueryじゃないとできないことが大幅に減った。標準APIでこなしたほうがいいだろう。

ajaxのasync/awaitでの書換

$.ajax(jQuery.ajax)の非同期処理をasync awaitの入れ子なし同期処理で記述する #JavaScript - Qiita

ajaxを使っている関数の定義にasync。ajax関数の使用箇所にawait。これでうまくいく。

**
 * フルーツ名を取得する
 *
 * @param {string} fruitId
 */
async function getFruitName(fruitId) {
  const fruitRequest = {id: fruitId}
  const fruitResult = await ajaxGetFruit(fruitRequest);
  return fruitResult.name;
}

/**
 * フルーツのajax[GET]を実施する
 * 
 * @param {object} request
 * @returns
 */
function ajaxGetFruit(request) {
  return $.ajax({
      url: '/fruit/name',
      type: "GET",
      async: true,
      contentType: "application/json",
      data: JSON.stringify(request),
      dataType: "json",
    }).then(
      function (result) {
        // 正常終了
        resolve(result);
      },
      function () {
        // エラー
        reject();
      }
    )
}

jQuery.ajax() | jQuery API Documentation」にあるように、jquery 1.5から$.ajaxの返却値はPromiseの派生クラス。そのまま返却させて良い。


Nuxt.js

終端スラッシュありへのリダイレクト

Nuxt.jsにおける末尾スラッシュを統一する方法 #amplify - Qiita

// middleware/trailingSlash.js
/**
 * 終端スラッシュありのURLにリダイレクトする。
 * @param {Object} Nuxt.jsのContextオブジェクト。
 */
export default ({ route, redirect }) => {
  if (route.path.endsWith('/')) {
    return
  }
  let to = route.path + '/'
  if (route.query) {
    to +=
      '?' +
      Object.entries(route.query)
        .map((e) => e.join('='))
        .join('&')
  }
  to += route.hash
  redirect(301, to)
}

//へのアクセスエラー

  • https://github.com/vuejs/vue-router/issues/2593
  • https://github.com/nuxt/nuxt.js/issues/2020

けっきょく、serverMiddlewareは結合環境で機能せず、middlewareもルートの変化後に発動するため対応できなかった。

そのため、プラグインにして、router.beforeEachで変化前に書き換え処理を入れた。

// plugins/redirect.js
export default ({ app }) => {
  app.router.beforeEach((to, from, next) => {
    // 二重スラッシュを一重スラッシュに変換する。
    // 素直にnextでリダイレクトすると、一度もともとのtoのURLでDOMの更新に進んでエラーが出る。
    // そのためnext(false)でtoは使わずにpushで履歴を差し替える。
    if (/\/\/+/.test(to.path)) {
      next(false)
      app.router.push(to.path.replace(/\/\/+/g, '/'))
    } else {
      next()
    }
  })
}

Vue.js

Naming

【Vue】単一ファイルコンポーネントの命名規則まとめ【ファイル名から記法まで】 #Vue.js - Qiita

radioのbool

vuejs2 - Vue: Binding radio to boolean - Stack Overflow

v-bind:か:で型を合わせて代入する。stringにするとうまく認識されない。

IMEの入力制限

IME以外はformatterで処理して、IMEだけcompositionendで処理すればいい。

<template>
  <div role="group" class="bv-no-focus-ring">
             <div
               class="form-group-text"
               :class="{ active: '' + value, 'is-invalid': error }"
             >
               <b-form-input
                 :id="'input-text-' + _uid"
                 type="text"
                 :formatter="formatter"
                 :value="value"
                 @input="$emit('input', $event)"
                 @compositionend="$emit('input', normalize($event.target.value))"
                 @paste="$emit('input', paste($event))"
               />
               <label :for="'input-text-' + _uid">{{
                 /[._]/.test(label) ? $t(label) : label
               }}</label>
    </div>
    <div :id="'input-live-feedback-' + _uid" class="invalid-feedback">
               {{ $t(error) }}
    </div>
  </div>
</template>
<script>
         export default {
           props: {
             value: { type: String, default: '', required: true },
    label: { type: String, default: '', required: true },
    // ファームウェアとスケジュールにエラーのないフォームがある。
    error: { type: String, default: '' },
  },
  methods: {
    /**
     * 入力内容の正規化を行う。
     * @param {string} input - 入力文字列。
     * @return {string} 正規化後文字列。
     */
    normalize(input) {
      // ASCII文字列以外は削除する。
      return input.replace(/[^ -~]/g, '')
    },
    /**
     * 入力フォームを整形する。
     * @param {string} value - 入力文字列。
     * @param {Object} event - イベントオブジェクト。
     * @return {string} IME変換時は正規化後の文字列。それ以外は、compositionendで行うため、未変換文字列。
     * IME変換時はcompositionendで入力を正規化し、それ以外はformatterで正規化する。
     */
    formatter(value, event) {
      return event.isComposing ? value : this.normalize(value)
    },
    /**
     * クリップボードからの貼付時の文字列を処理する。
     * @param {Object} event - イベントオブジェクト。
     * @return {string} 処理後の文字列。
     * @todo 入力の途中にカーソルを移動させて貼り付けた場合、貼り付け後、カーソルが末尾に移動してしまう。
     * event.preventDefault()が原因と思われる。しかし、これの解決が難しい。
     * event.target.selectionStartにカーソル位置を指定できるのだが、preventDefaultすると一瞬カーソルが末尾に飛ぶ。
     */
    paste(event) {
      event.preventDefault()
      const cb = (event.clipboardData || window.clipboardData).getData('text')
      const start = event.target.selectionStart
      return this.normalize(
        this.value.slice(0, start) + cb + this.value.slice(start)
      )
    },
  },
}
</script>
<template>
  <div role="group" class="bv-no-focus-ring mb-3">
             <div
               class="form-group-text"
               :class="{ active: '' + value, 'is-invalid': error }"
             >
               <b-form-input
                 :id="'input-number-' + _uid"
                 class="form-control"
                 type="tel"
                 autocomplete="off"
                 maxlength="10"
                 :formatter="formatter"
                 :value="value"
                 @input="$emit('input', $event)"
                 @compositionend="$emit('input', normalize($event.target.value))"
               />
               <label :for="'input-number-' + _uid">{{ $t(label) }}</label>
    </div>
    <div :id="'input-live-feedback-' + _uid" class="invalid-feedback">
               {{ $t(error) }}
    </div>
  </div>
</template>
<script>
         export default {
           props: {
             value: { type: [String, Number], default: '', required: true },
    error: { type: String, default: '', required: true },
    label: { type: String, default: '', required: true },
  },
  methods: {
    /**
     * 入力内容の正規化を行う。
     * @param {string} value - 入力文字列。
     * @return {string} result - 正規化後文字列。
     * @warn v-model.numberの修飾子を指定するとcompositionendでの変更が反映されない。
     * そのため、.numberを使わず、この関数で型変換する。
     */
    normalize(value) {
      const result = parseFloat(value.replace(/[^0-9]/g, ''))
      return isNaN(result) ? '' : result
    },
    /**
     * 入力フォームを整形する。
     * @param {string} value - 入力文字列。
     * @param {Object} event - イベントオブジェクト。
     * @return {string} IME変換時は正規化後の文字列。それ以外は、compositionendで行うため、未変換文字列。
     * IME変換時はcompositionendで入力を正規化し、それ以外はformatterで正規化する。
     */
    formatter(value, event) {
      return event.isComposing ? value : this.normalize(value)
    },
  },
}
</script>

error '<template>' cannot be keyed. Place the key on real elements instead vue/no-template-key

vue.js - Custom elements in iteration require 'v-bind:key' directives - Stack Overflow

ハイライト

https://forum.vuejs.org/t/highlight-in-html-a-new-object-in-javascript-array/38877/9

nextTickでやればいいか。

【Vue.js】検索文字などの特定文字を、マーカーでハイライト表示するコンポーネントを作った | SAGA.TXT

検索キーワードで検索対象をsplitして、key/value形式で順番に配列で配置する。

カスタムコンポーネントのv-bind

javascript - How to use v-bind in a custom component? - Stack Overflow

using v-model b-input component · Issue #1038 · buefy/buefy