20200807のJavaScriptに関する記事は16件です。

Array.prototype.filterメソッドを甘く見ていた…

今まであまり意識しなかったのですが、配列要素を削除する際に5行以上かけていたのですが、1行でシンプルに完結できて感動したので共有します。

今までの自分のコード

const array = [0, 1, 2, 3, 4];

console.log(`before : array = ${array}`);

array.forEach((item, index) => {
    if(item === 1) {
        array.splice(index, 1);
    }
});

console.log(`after : array = ${array}`);

今後

const newArray = array.filter(n => n !== 1);

(*IEで動かすには、BabelやTypescriptでコンパイルする必要があります)

今まで自分が書いてたコードの拙さを思い知らされました…

関数型プログラミングという概念があります。
JavascriptでいうとElmが有名かと思います。
最近になって知り合いの話を聞くと、この関数型プログラミングを学んでおくと、かなりエンジニアとしての地力がつくと教えられました。
その知人は、Elmを学んだ事でTypescriptやReact, Reduxといった概念がスッと理解できるようになったとか。

他にも、(知り合いの超スゴいエンジニアの方いわく)今や、JSでfor分を使うのはあまりパフォーマンスの観点からよくなくて、Array.prototype.reduceを使うのが良いらしいです。
調べて見たら、こちらも(使いこなせるようになるまで時間はかかりそうですが)体得できればよりシンプルにコードを書けそうです。
関数型プログラミングの一種だそうです。

………コードの書き方1つとっても、奥が深くて覚える事がいっぱいだーーーー!!!!(だからこそ、プログラミングは面白い)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactでデータグリッド/テーブルを実装するときに見てほしいおすすめコンポーネント集

データグリッド

Reactでデータグリッドを実装したいときにおすすめしたいコンポーネント集です。
Material UIが好きなので、Material UIを使っている私の目線でのコメントが多いですが、ご容赦ください。

まだ実装お試ししていないけど良さそうなものがいくつかあるので、少しづつ追加しますよ :D

コンポーネント集

見る専部門

データを見せることに向いている系です。

Material UI - Table Component

Table React component - Material-UI
MaterialUI純正のテーブルコンポーネントです。ソートやフィルタは自分で実装してイベントで差し込んでいく感じですね。仮想テーブルもできますが、他のライブラリとのあわせ技なので、このコンポーネントの特徴ってことでもないですね。なにより、Material UIの純正なので、Material UIをアプリの全体荷適用しているなら第一候補ですね。見た目もスッキリ統一感が出ますしね。あとはなんて言ったって、Material UIはデモページもAPIのページもとっても詳しい。ありがたい。

React-Table

tannerlinsley/react-table

Reactのテーブルといえばこれですね。名前もそのままReact-Table。いろいろな方がコントリビュートしてくれているので、やりたいことはなんだってできるような印象です。デモページもとっても豊富でわかりやすいですね。Material UIにこだわらないなら、第一候補ではないでしょうか?ちょっと見た目の調整は頑張らないといけないかもしれないですね。Style差し込んで行きましょう。

Grid.js

Grid.js - Advanced table plugin

比較的新しいライブラリです。TypeScriptで実装されているのがいいですね!新しい割にGitHubスター数が結構多いので、これからグイグイくるんじゃないかなぁ、という期待と、TypeScriptを採用しているので仲良くなれそうだなぁという理由から、序盤で紹介させていただきました。見た目もかっこいいですね。

Material-table

mbrn/material-table

Materialデザインを踏襲して実装されたテーブルコンポーネントですね。Material UIのサイトでも紹介されているので、公式もその良さを認めているのかな?テーブル自体の操作感はよく、いいコンポーネントだと思います。

mui-datatables

gregnb/mui-datatables

Material-table と対を成すのが、mui-datatablesです。テーブル自体の操作感はかなり良いです。デモページも結構見やすくて、見ているだけでも楽しくなるので、おすすめです。gregnb/mui-datatables

SpreadSheet寄り編

データを見ながらちょちょっと修正したいときに便利なコンポーネントです。ほとんどExcelじゃん、ってのもあります。

react-data-grid

React Data Grid · Excel-like data grid component built with React

Excelライクな感じになっているが、それなりにWeb感も残しています。Excelほど自由自在にコピペできる感じではないのがちょっと惜しい。

React Datasheet

React Datasheet Component

かなりExcelライクな感じですね。テーブルのほとんどの要素を編集可能にしないといけないケースには向いていそうですね!

ブルジョワ編

金の力は偉大だ!!!

ReactGrid (有償)

React Grid

なにもいうことはないです。すげーよ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSでHTML上の添付ファイル取得とダウンロード

JSで添付ファイルを拾うのと、ファイルを落とす処理の実装サンプル的ななにか

<html>
<head>
  <meta charset='utf-8'>
  <title>js file up/dl example</title>
  <script>
    window.onload = () => {
      const fr = new FileReader();
      const el = document.getElementById("test");

      fr.onload = (ev) => {
        const dl = document.createElement('a');
        dl.setAttribute('href', ev.target.result);
        dl.setAttribute('download', el.files[0].name);
        dl.style.display = 'none';
        document.body.appendChild(dl);
        dl.click();
        document.body.removeChild(dl);
      };

      el.addEventListener("change", () => {
        fr.readAsDataURL(el.files[0]);
      });
    };
  </script>
</head>
<body>
  <input type="file" id="test"></input>
</body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

継続渡しスタイル(CPS)チートシート

例によって,少なくとも約1名(自分自身)には役立ちそうだったので,各言語の継続渡しスタイル(Continuation-passing style,CPS)のサンプル記述を記事としてまとめた.

Python(Python 3):解説付き

対話モードで,xに10を代入してから,x + 20を評価させてみる.

>>> x = 10
>>> x + 20
30

このプログラム記述をファイルにしてPythonインタプリタに実行させても,何も表示されない.対話モード(REPL)では,式として評価されたものはその結果を表示するのに対し,ファイル実行(スクリプト)では,そのような表示は行わないためである.

C:\Users\hoge>type sample.py
x = 10
x + 20
C:\Users\hoge>python sample.py

C:\Users\hoge>

もし,ファイル実行で評価結果を表示させたい場合は,評価結果を得た後に,たとえばprintを用いて表示させるようにする必要がある.

C:\Users\hoge>type sample.py
x = 10
print(x + 20)

C:\Users\hoge>python sample.py
30

C:\Users\hoge>

ここで,式として記述する場合は,評価結果を処理する関数を必ず指定しなければならない仕組みを考える.次は,x + 20を評価したら,その評価結果を関数fに引数として渡して呼び出す関数cadd20を定義し,fprintを指定して実行した例である.

C:\Users\hoge>type sample.py
def cadd20(x, f): f(x + 20)
x = 10
cadd20(x, print)

C:\Users\hoge>python sample.py
30

C:\Users\hoge\python>

このように,結果を処理する手続きをあらかじめ指定する仕組みを想定したプログラミング手法を『継続渡しスタイル』(continuation-passing style,CPS)と呼ぶ.このスタイルは,そうとは意識されない形を含め,様々な実装に応用されている.

  • コールバック関数(指定する手続き)とハンドラー(呼び出す関数)
  • 例外処理のtry(呼び出す手続き)とexcept(指定する手続き)
  • CPSに自動変換して明確となった値受け渡しからの中間言語記述生成

なお,関数のCPSへの変換は容易であるが,変換した関数を使用するには工夫が必要である.ここでは,既存関数のCPSへの変換と利用例を示す(このチートシートの本体).

from operator import add, sub, mul

# func(x, y) = (x + y) * (x - y)
def func(x, y): return mul(add(x, y), sub(x, y))

print(func(10, 20))    # => -300

def cps(f):
    def cps(x, y, c): return c(f(x, y))
    return cps

cps(add)(10, 20, print)    # => 30

def cfunc(x, y, c):
    return cps(add)(x,  y,  lambda c1:    # x + y -> c1
           cps(sub)(x,  y,  lambda c2:    # x - y -> c2
           cps(mul)(c1, c2, c)))          # c1 * c2 -> c

cfunc(10, 20, print)    # => -300

Scheme(Gauche,Guile)

; func(x, y) = (x + y) * (x - y)
(define (func x y) (* (+ x y) (- x y)))
(display (func 10 20))    ; => -300

(define (cps f) (lambda (x y c) (c (f x y))))
((cps +) 10 20 display)    ; => 30

(define (cfunc x y c)
  ((cps +) x y (lambda (c1)    ; x + y -> c1
  ((cps -) x y (lambda (c2)    ; x - y -> c2
  ((cps *) c1 c2 c))))))       ; c1 * c2 -> c
(cfunc 10 20 display)    ; => -300

Ruby(CRuby)

# func(x, y) = (x + y) * (x - y)
def func1(x,y) (x+y)*(x-y) end
p func1(10,20)    # => -300

add = -> x,y { x+y }
sub = -> x,y { x-y }
mul = -> x,y { x*y }
prn = -> x { p x }

cps = -> f { -> x,y,c { c.(f.(x,y)) } }
cps[add][10,20,prn]    # => 30

cfunc = -> x,y,c {
  cps.(add).(x, y, -> c1 {     # x + y -> c1
  cps.(sub).(x, y, -> c2 {     # x - y -> c2
  cps.(mul).(c1,c2,c) }) })    # c1 * c2 -> c
}
cfunc[10,20,prn]    # => -300

JavaScript(Node.js)

// func(x, y) = (x + y) * (x - y)
function func1(x,y) { return (x+y)*(x-y) }
console.log(func1(10,20))    // => -300

add = (x,y) => x+y
sub = (x,y) => x-y
mul = (x,y) => x*y

cps = f => (x,y,c) => c(f(x,y))
cps(add)(10,20,console.log)    // => 30

cfunc = function(x,y,c) {
    return cps(add)(x, y, c1 =>    // x + y -> c1
           cps(sub)(x, y, c2 =>    // x - y -> c2
           cps(mul)(c1,c2,c)))    // x * y -> c
}
cfunc(10,20,console.log)    // => -300

備考

記事に関する補足

  • そのうち『Iコンビネータ』に関する説明を追加するかもしれない(謎).

参考文献

変更履歴

  • 2020-08-09:Schemeのcall/cc利用例削除(Twitterコメントより)
  • 2020-08-07:参考文献欄を追加
  • 2020-08-07:JavaScriptの例を追加
  • 2020-08-07:初版公開(Python,Scheme,Ruby)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js (JavaScript)でセミコロンを付けていなかったことで "TypeError: require(...) is not a function"が発生していた(JavaScriptの構文について)

今日JavaScript(Node.js)を書いていたときに遭遇した出来事を備忘録がてら書き残しておく。

エラーになったコード

下記のコードはエラーになる。

const fs = require('fs')

(async () => {
  console.log(fs)
})()

実行結果

(async () => {
^

TypeError: require(...) is not a function

上のエラーを解決させたコード

JavaScriptは;を書こうが書かまいがが動く、と思っていたが、1行目の末尾に ; をつけることで、今回のコードは問題なく動くようになる。

const fs = require('fs');

(async () => {
  console.log(fs)
})()

※実行結果は長くなるので省略。サンプルコードが悪かった...

"TypeError: require(...) is not a function"が出る仕組み

これはどういうことかなと思ったけど、考えてみれば単純なことだった。

JavaScriptは文末にセミコロンを付けなかった場合、その後の文が構文的に解釈可能な場合、解釈しようとする。
自分もここらへんは自信がないので、JavaScript Primer の記述も引用させていただく。

JavaScriptには、特殊なルールに基づき、セミコロンがない文も行末に自動でセミコロンが挿入されるという仕組みがあります。 しかし、この仕組みは構文を正しく解析できない場合に、セミコロンを足すという挙動を持っています。 これにより、意図しない挙動を生むことがあります。そのため、必ず文の末尾にはセミコロンを書くようにします。

引用元のページ: https://jsprimer.net/basic/statement-expression/#statement-expression-summary

つまり先ほど私が書いたコードは下記のように解釈された形となる。

// require('fs')(/* ~ */) 的な解釈となっていた
const fs = require('fs')(async () => { 
  console.log(fs) 
})()

余談: prettierでセミコロンを付けない設定をした際の挙動

気になったので試してみた。

prettier の設定で semi: false にしたとき、;はどこにつくのか?
結果は下記の通り。

const fs = require('fs')

;(async () => {
  console.log(fs)
})()

あとがき

普段 ; は付ける派なのだが、なんとなくプロトタイプのコードを書いていてつけないでいた。後から prettier かければ済む話だとか考えていたら、思わぬエラーに引っかかった。
おかげでJavaScriptのことを少し知ることができたので結果的に良かったと思う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テキストからWindowsのファイル名に使えない記号を置き換えるコード

Windowsのファイル名に使えない記号\ / : * ? " < > |を全角記号に置き換えるだけのコードです。
テキストをstrの中に入れてお使い下さい。テンプレートリテラルなので改行ありでも大丈夫です。
そのままブラウザからF12 → consoleに打ち込めば結果が出ます。

コード

var str =
`
text
`;

console.log(
    str.replace(/\\/g, "")
       .replace(/\//g, "")
       .replace(/:/g, "")
       .replace(/\*/g, "")
       .replace(/\?/g, "")
       .replace(/"/g, "")
       .replace(/</g, "")
       .replace(/>/g, "")
       .replace(/\|/g, "")
);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Nuxt.js】Nuxt実践編:あると便利なコピーボタンの作り方

? この記事はWP専用です
https://wp.me/pc9NHC-xv

前置き

ここ最近は文法編に力を入れていたので
久しぶりの実践編です✨

Frame 1.png

input内のテキストを
コピーするボタンを作ってみましょう♪
イベントアプリなどでページを作成し、
自動生成されたurlをコピーしたい時なんかに使えます?

urlの自動生成まではやりません。
あくまでinputとコピーボタンのみ作成します??
スタイリングも省いてます、そこはお好みで♪

まずはinputを作成

コピーボタンの作り方は
3通り用意していますが、
input部分はどれも共通です?

divではダメなのか

今回はコピーボタンがあるので
値が見えなくても@clickでコピーさえできればOK⭕️
そのためinputでやっていますが、
urlを直接選択するような場合は
スクロールの効くdivで作成すると良いと思います?

divで作る場合も後述しておきます✍️

解説

readonly属性
urlを間違って編集したりしないようにします⚠️

:value
今回はユーザーが入力する必要がないので
@inputが不要、双方向バインディングが不要です?
値だけバインドできればOK⭕️

class="text"
input要素ではありますが、
入力不要でテキスト表示の役割のため。
コンポーネントにする場合も
InputText.vueなどの命名にし、
$attrsを使うのが良いと思います?

⬇️双方向バインディング、
 v-modelについてはこちら
 https://wp.me/pc9NHC-kI

コード

index.vue
<template>
 <div class="page">
   <input
     id="input"
     :value="url"
     type="text"
     readonly
     class="text"
   >
 </div>
</template>

<script>
export default {
 data () {
   return {
     url: 'https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb',
   }
 },
}
</script>

コピーボタンを作る

コピーと言えばdocument.execCommand()ですが廃止!
なのでClipboard APIと
nuxt-clipboard2を使ってみましょう?

document.execCommand()も
一応…最後に載せています?

方法1: Clipboard API

? 続きはWPでご覧ください?
https://wp.me/pc9NHC-xv

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VeeValidateを使ってVueアプリでバリデーションをする

VeeValidate

VeeValidateは以下の特徴を備えたVue.jsのバリデーションライブラリーです。
ドキュメントを読みつつ訳しながらまとめた内容です。

https://logaretm.github.io/vee-validate/

  • テンプレートベースのバリデーション
  • 多彩なバリデーションルールがデフォルトで用意済み
  • 一級のローカライゼーションサポート
  • HTML5のinputフォームとカスタムコンポーネントのバリデーションが可能
  • カスタムルールとエラーメッセージも作成可能

はじめよう

利用方法

まずVueのインスタンスに登録します。

import Vue from 'vue';
import VeeValidate from 'vee-validate';

Vue.use(VeeValidate);

コンフィグ設定したいならこちらの方法。

import Vue from 'vue';
import VeeValidate from 'vee-validate';

const config = {
  // config that you want
}

Vue.use(VeeValidate, config);

ベーシックな例

inputフォームにv-validateディレクティブとname属性を追加するだけでOKです。name属性はエラーメッセージの生成に利用されます。
v-validateディレクティブにはルールを設定します。パイプ|を間に挟むことで複数のルールが適用可能です。
以下は「必須、かつ、eメールの形式であること」の例です。

<input v-validate="'required|email'" name="email" type="text">

エラーメッセージを表示するにはerrors.firstメソッドを利用することでその項目の最初のエラーが取得できます:

<span>{{ errors.first('email') }}</span>

Tips
v-validateに定義された値はシングルクォートで囲われています。これはディレクティブに与えられた内容はJavaScriptとして評価されるためです。
シングルクォートで囲むことでString型であることを明示的にする必要があります。
v-validate="required"としてしまうとrequiredというおそらく存在しないであろう変数や関数を参照しようとしてしまいます。

シンタックス

バリデーションルールはString型での定義や、プログラマブルにしたい時はObject型での定義も可能です。

// String
const single = 'required'
const multiple = 'required|numeric'

// Object
const single = { required: true }
const multiple = {
  require: true,
  numeric: true
}

ルールのパラメーター

ルールの一部はパラメーターを持つことができます。パラメーターは複数の定義方法が可能です。

  • String型ならカンマ区切りの値
  • Object型なら配列の値
  • Object型でより複雑なパラメーターならオブジェクト
// String型のパラメーター
const someRule = 'included:1,2,3,4';

// Array型のパラメーター
const someRuleObj = { included: [1, 2, 3, 4] };

// Object型のパラメーター
const someCplxObj = {
  email: {
    allow_utf8_local_part: true
  }
};

ルールの実例

上の内容を実例でみてみましょう。

  • 必須のEメールの入力欄
<input v-validate="'required|email'" type="email" name="email">
<input v-validate="{ required: true, email: true }" type="email" name="email">
  • 必須でないユーザー名の入力欄
<input v-validate="'alpha'" type="text" name="username">
<input v-validate="{ alpha: true }" type="text" name="username">
  • 必須かつ最低6文字のパスワード入力欄
<input v-validate="'required|min:6'" type="password" name="password">
<input v-validate="{ required: true, min: 6 }" type="password" name="password">

エラーの表示

エラーメッセージが生成されると、エラー表示簡易化のために用意されたErrorBagインスタンスに保存されます。

デフォルトではErrorBagのインスタンスはerrorという名前で各コンポーネントのcomputedプロパティにインジェクトされます。
errorという名前は競合を避けるためにコンフィグからカスタマイズ可能です。

エラーメッセージを1つ表示する

一般的には1つのフォームに対して1つのエラーを表示することが多いと思います。これはerrors.first('fieldName')メソッドでエラーを取得可能です。

<input type="text" name="fieldName" v-validate="'required'">
<span>{{ errors.first('fieldName') }}</span>

Tips
VeeValidateのデフォルトでは1フィールドに対して1エラーしか生成しません。これはバリデーションパイプラインの高速化が理由です。
複数のバリデーションエラーのメッセージを同時に生成したい場合はfastExitオプションをコンフィグからカスタマイズしてください。
あるいは、特定のフォームだけに適用したい場合はcontinuesmodifilerの適用も可能です。v-validate.continues="'required|numeric'"

エラーメッセージを複数表示する

1つのフォームに複数のエラーを表示したい場合はerrors.collect('fieldName')メソッドが利用できます。
このメソッドは1つのフィールドに紐づくエラーメッセージを配列で返します。

<input type="text" name="fieldName" v-validate.continues="'required|alpha|min:5'">
<ul>
  <li v-for="error in errors.collect('fieldName')">{{ error }}</li>
</ul>

全てのエラーメッセージを表示する

errors.all()を使いフラットなエラーメッセージの配列を取得できます。

<input type="text" name="first" v-validate.continues="'required|alpha|min:5'">

<input type="text" name="second" v-validate.continues="'required|alpha|min:5'">

<ul>
  <li v-for="error in errors.all()">{{ error }}</li>
</ul>

フィールド名ごとにグルーピングしたい場合は、errors.collect()を引数無しで利用します。
キーがフィールド名で値がエラーメッセージの配列のオブジェクトが取得できます。

<input type="text" name="first" v-validate.continues="'required|alpha|min:5'">

<input type="text" name="second" v-validate.continues="'required|alpha|min:5'">

<ul>
  <li v-for="group in errors.collect()">
    <ul>
      <li v-for="error in group">{{ error }}</li>
    </ul>
  </li>
</ul>

バリデーションルール

いっぱいあるよ。

https://baianat.github.io/vee-validate/guide/rules.html

カスタムコンポーネントのバリデーション

VeeValidateはHTML5のinput要素だけでなくカスタムコンポーネントのバリデーションも対応しています。
カスタムコンポーネントでの利用はいくつか注意が必要です。このトピックではその注意点について説明します。

どう動くか

カスタムコンポーネントを入力欄として動作させるのにv-modelを利用して値を扱うことは一般的です。
VeeValidateはこの値を$watch APIを利用して監視していますが、$watchには制限があります。
たとえば、v-forのイテレーターの値はv-forのループのコンテキストとしてしか存在していないため監視できません。

VeeValidateはvalueのpropを監視するようフォールバックします。
もしコンポーネントがmodelコンストラクタをカスタマイズしている場合でも、正しいプロパティを検出しそれを監視します。

このデモはVeeValidateとVuetifyのカスタムコンポーネントを組み合わせた例です。

以上はほとんどのケースをカバーしますが、v-modelを利用して値を取り回していない場合は対応できません。
そのようなケースではコンポーネントのコンストラクターオプションを利用することでより細かなバリデーションの挙動を設定することができます。

コンポーネントのコンストラクターオプション

バリデーターのカスタムコンポーネントへの挙動をカスタマイズすることにより不要な属性の追加などを防ぐことができます。
これは$_veeValidateフィールドをカスタムコンポーネントに定義することで実現します:

export default {
  // ...
  data: () => ({
    // コンポーネント内部のデータ
    innerValue: 'initial'
  })
  $_veeValidate: {
    // バリデーションの対象とするデータ
    value () {
      return this.innerValue;
    }
  },
}

$_veeValidateではvalue含めて以下が設定可能です。

プロパティ 種類 初期値 説明
name () =>, string undefined エラーメッセージの生成に使われる名前
value () =>, any undefined バリデーションの対象となる値
rejectFalse boolean false falserequiredに対してバリデーションエラーとなるか
events string `input blur`
validator string new or null コンポーネントがバリデータのインスタンスをどう得るか。newの場合は新しいバリデーターインスタンスを生成して利用する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Puppeteer 文字列で 特定の要素を選択したい時、またその文字列の近くの要素をクリックしたい時

Puppeteer 文字列で 特定の要素を選択したい時、

またその文字列の近くの要素をクリックしたい時

なぜ文字列で選択したいか

・Xpath脳死コピペ
・HTMLタグ
・クラス名やID名
では限定しきれない時があるから

例えば
Yahoo!広告アカウントに送られてくる特定の名前のレポートのみをクリックしたい時
(あくまで抽象化するための例)

ポイントは2点

①文字列で選択する方法
②その文字列自体をクリック・抽出しても意味がない
aタグまでパスを渡す

結論:Xpathあんま理解してなかったのが俺が悪い

app.js
const reportPath =
    "//span[contains(text(), 'hogehoge')]/../..//a";

await page.waitForXPath(reportPath);
const reportClick = await page.$x(reportPath);
await reportClick[0].click();

``

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript + SimpleBar: スクロールバーのスタイルをカスタマイズする

SimpleBarはスクロールバーをカスタマイズするライブラリです。スクロールバーを独自につくるのではなく、CSSのスタイルを割り当てるので、おかしな挙動は起こらず、ネイティブなスクロールのパフォーマンスが保たれます。あくまで、スクロールバーの見栄えを変えるだけです。

SimpleBar logo

デザインはCSSで定める

SimpleBarは純粋なCSSでスクロールバーのスタイルを定めます。CSSで与えられるスタイルでさえあれば、自由にカスタマイズできるのです。

軽量なライブラリ

6KBのとても軽いライブラリです。JavaScriptはスクロールの動きそのものには触れません。ネイティブな動きとパフォーマンスが得られます。

モダンブラウザをサポート

ChromeとFirefox、Safariなどのモダンブラウザに加え、Internet Explorer 11をサポートします。

ライブラリの概要はドキュメントデモページでお確かめください。本稿でつくるのは、つぎのサンプルです。「JavaScript + CSS: ヘッダを上部に固定してカラムの中身はスクロールさせる」のコードにSimpleBarのスタイルを割り当てました。

See the Pen JavaScript + SimpleBar: Customizing scrollbar style by Fumio Nonaka (@FumioNonaka) on CodePen.

インストール

インストールには、npmやyarnが使えます。

npm install simplebar --save
yarn add simplebar

また、unpkgとjsDeliverからCDNで読み込むこともできます。JavaScriptとCSSのライブラリがそれぞれ必要です。

<link
  rel="stylesheet"
  href="https://unpkg.com/simplebar@latest/dist/simplebar.css"
/>
<script src="https://unpkg.com/simplebar@latest/dist/simplebar.min.js"></script>
<!-- または -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/simplebar@latest/dist/simplebar.css"
/>
<script src="https://cdn.jsdelivr.net/npm/simplebar@latest/dist/simplebar.min.js"></script>

バージョンを固定したいときは、@latestをバージョン番号に置き替えてください。たとえば、本稿執筆時の最新リリース版であれば、@5.2.1です。unpkgでバージョンのリストが確かめられます。

なお、Webpackなどのモジュールローダーを使う場合には、JavaScriptとCSSのライブラリをimportしてください。

import SimpleBar from 'simplebar';
import 'simplebar/dist/simplebar.css';

data-*グローバル属性で設定する

SimpleBarのもっとも簡単な使い方は、スクロールバーを加えたい要素にdata-*グローバル属性としてdata-simplebarを与えることです。なお、スクロールさせる要素には、CSSでoverflow: autoを定めてください。

<div data-simplebar>
  <!-- コンテンツ -->
</div>

これだけで、要素にはSimpleBarのスタイルでスクロールバーが表示されます(図001)。デフォルトでは、要素にマウスポインタを重ねたときバーが表れる自動表示の設定です。

図001■設定されたスクロールバー

2008001_001.png

つねにスクロールバーを表示しておきたいとき、タグに加えるオプション属性はdata-simplebar-auto-hideです。JavaScriptコードの場合には、autoHideオプションを用います。

<div data-simplebar data-simplebar-auto-hide="false"></div>

JavaScriptコードでSimpleBarを要素に設定する

JavaScriptコードで要素にSimpleBarを設定する場合は、SimpleBar()コンストラクタに要素の参照を渡すだけです。

new SimpleBar(document.getElementById('myElement'));

オプションは、コンストラクタの第2引数のオブジェクトにプロパティとして渡します。たとえばつぎのコードはスクロールバーの自動表示(autoHide)をオフにする場合です(デフォルト値はtrue)。

new SimpleBar(document.getElementById('myElement'), { autoHide: false });

CSSでスクロールバーのスタイルを変える

SimpleBarのスクロールバーのスタイルは、CSSにより定められています。つまり、見栄えがCSSで変えられるということです。ここでは、スクロールさせるスライダのカラーをグラデーションにしてみましょう(図002)。こうしてでき上がったのが、冒頭のCodePenのサンプルです。

.simplebar-scrollbar::before {
    background: linear-gradient(darkblue, skyblue);
}

図002■スライダのカラーがグラデーションになった

2008001_002.png

SimpleBarのスクロールバーのCSSは、つぎの4つのクラスをもとに組み立てられています。具体的な定めについては、ソースコードsimplebar.cssをご参照ください。

  • simplebar-content スクロールするコンテンツを包むラッパー
  • simplebar-scroll-content スクロールする要素が収められたコンテナ
  • simplebar-scrollbar ユーザーがコンテンツを操作するスクロールバーのスタイルの定め
  • simplebar-track スクロールバーが置かれた領域のスタイル
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

やさしいりあくとのはじめかた

この記事は株式会社富士通システムズウェブテクノロジーが企画するいのべこ夏休みアドベントカレンダー 2020の27日目の記事です。本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。

はじめに

本記事ではFacebook社のJavaScriptのSPAライブラリのReactについて紹介したいと思っています。

プロジェクトでフロントエンド基盤を整備することを目的に2020年4月に0からReactを勉強してきました。

この経験を踏まえ、React興味あるけど勉強の仕方がわからない、SPAを作ってみたいという方にとって、React開発を始めるきっかけになれればいいと思っています。

SPA(Single Page Application)ってなに?

SPAとは単一のWebページでアプリケーションを構築するアーキテクチャです。

サーバーサイドWebとSPAと比較すると...
コメント 2020-08-06 174704.jpg
上の画像を見てわかる通り、SPAは極力サーバーへのリクエストを減らし、単一のWebページのみを使用して、効率よくWebページの表示ができます。

今が熱いReact

3大SPAフレームワーク/ライブラリは、

  • React.js
  • Vue.js
  • Angular.js

がありますけど、ランキングはこんな感じ

ダウンロード数(2020/08/06現在)

コメント 2020-08-06 180954.jpg
reactの圧倒的ダウンロード数!!!!

githubスター数(2020/08/06現在)

コメント 2020-08-06 181013.jpg
vueとreactがいい勝負。

こんな感じでいろんな人がReactをダウンロードして開発している

npm trends react vs vue vs angular
https://www.npmtrends.com/react-vs-vue-vs-angular

はじめてのアプリ作成

さっそく、Reactアプリケーションを作ってみよう!

準備

下記のツールを自分の端末にインストール!

YARNを導入

npm install --global yarn
もしくは
npm i -g yarn

プロジェクト作成

JavaScript版でReactプロジェクトを作成する場合
npx create-react-app [プロジェクト名]
TypeScript版でReactプロジェクトを作成する場合
npx create-react-app [プロジェクト名] --typescript

プロジェクト起動

作成したプロジェクトまで移動
cd [プロジェクト名]
プロジェクトの起動
yarn start

http://localhost:3000/ で下の画面が表示される!
コメント 2020-08-05 150115.jpg

Hello World!を表示する

フォルダ構成はこんな感じ
コメント 2020-08-05 150942.jpg

src/App.jsもしくはsrc/App.tsxを開いて、以下の内容を変更して保存!

src/App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
-         Edit <code>src/App.js</code> and save to reload.
+         Hello World!
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}
export default App;

ロゴ画像の下に「Hello World!」と表示される
コメント 2020-08-05 152011.jpg
とっても簡単。

りあくとのはじめかた

Reactの習得する方法は以下の流れ

  1. JavaScriptの習得
  2. (TypeScriptの習得) ※必要がある人だけ
  3. Reactの習得

おすすめ勉強サイト/書籍
現代の JavaScript チュートリアル
りあクト! TypeScriptで始めるつらくないReact開発 第2版
React 公式サイト
TypeScript 公式サイト

やってはいけないこと

  • いきなり完成されたコードを読もうとする
  • HTML、CSS、JavaScriptの知識がない状態でReactの開発に臨む
  • Reactの設計思想を知らない状態で開発を始める

基礎からちょっとずつ進めることをお薦めします。

みんなの反応

2020年7月17日(金)にウェブテクデーを使用して、チーム内でReact勉強会を開催しました。
私が講師として進めていました。開催後のみんなの反応はこんな感じです。

H・Hさん
従来型のウェブ開発ばかりやっていると、モダンなJavaScript(ES6以降)の知識がコードが全く読めないことを痛感した。新しい技術に触れないとだめだなと感じたし、特にフロントエンドは流れが素早いと思った。

E・Hさん
C#やJavaScript(ES5以前)はやってみたことがあったが、
今日の勉強会を通して、JavaSciprt(ES6以降)は新しい言語で臨むつもりで勉強しないといけないと感じた。
ただ、JavaScriptの新しい機能は便利だと思ったし、SPAの仕組みについても知れてよかった。
家でももっとやりたいと感じた。

T・Sさん
業務チームのある程度の水準でスキルを均一化をどう図るかが今後の課題になってくる。

Y・Sさん(React学習経験あり)
私は山田と一緒に1週間ペアプログラミングを行い、Reactを学びました。短い期間ですが、体験してみて感じたことは技術を学ぶ際には、必ず基礎から始めるべきだとということです。いきなり完成されたコードを読み込んでも、読めなくて挫折するだけです。
私はReactの学習を下記の流れで行いました。私はこれである程度実装できるようになりましたよ!
① HTML、JavaScript(TypeScript)の知識を習得する
 りあクト! TypeScriptで始めるつらくないReact開発 第2版 ← これ本当におすすめ!
② Reactの公式ドキュメントの最初のページを読んで、Reactで何ができるかを知る
③ React公式ドキュメントに記載されているチュートリアルを行い、小さいコンポーネントから開発

コメント 2020-08-07 184907.jpg

おわりに

4月から勉強を開始して、2か月間がっつりReactを独学で勉強しました。
フロントエンドの開発自体、あまり経験がなく学習にすごく苦労しましたが、
最終的にはウェブテクデーで人に教えられるレベルまで成長できたので良かったです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptでアナログ時計を作成

今回はjavascriptでアナログ時計を作ってみました。


なぜ作ったか


アナログ時計なので
時間周りの処理が必要なのでそこらへんの勉強になるのと、
あまりwebサイトではアナログ時計を見ないですが、サイトにあったら意外とお洒落かもと思って
作ってみました。


作るアナログ時計の完成イメージ


スクリーンショット 2020-08-07 10.04.29.png


基本的な丸型の時計です。


コード


html


まずはアナログ時計の元になるhtmlを書いていきます。
必要なhtmlはごく少量です。
大きく分けて、必要なのは


  • 外枠
  • 時針
  • 分針
  • 秒針
  • 時間の文字

これだけです。


<div class="c-clock"> // 外枠
  <span class="c-clock__hour"></span> <!-- 時計 -->
  <span class="c-clock__min"></span> <!-- 分針 -->
  <span class="c-clock__sec"></span> <!-- 秒針 -->
  <span class="c-clock__12">12</span> <!-- 時計文字 -->
  <span class="c-clock__3">3</span> <!-- 時計文字 -->
  <span class="c-clock__6">6</span> <!-- 時計文字 -->
  <span class="c-clock__9">9</span> <!-- 時計文字 -->
</div>

ちなみにbem記法で書いてるので気になる方はこちらも
https://qiita.com/w-tdon/items/2ede0122286f88db472f


css


.c-clock {
  position: relative;
  width: 400px;
  height: 400px;
  border: 1px solid #333;
  border-radius: 50%;
}
.c-clock__hour {
  position: absolute;
  top: calc(50% - 150px);
  left: calc(50% - 5px);
  width: 10px;
  height: 150px;
  background: #333;
  transform-origin: bottom;
}
.c-clock__min {
  position: absolute;
  top: calc(50% - 180px);
  left: calc(50% - 2px);
  width: 4px;
  height: 180px;
  background: #333;
  transform-origin: bottom;
}
.c-clock__sec {
  position: absolute;
  top: calc(50% - 200px);
  left: calc(50% - 1px);
  width: 2px;
  height: 200px;
  background: #ff0000;
  transform-origin: bottom;
}
.c-clock__12 {
  position: absolute;
  top: 10px;
  left: calc(50%);
  transform: translateX(-50%);
  font-size: 18px;
}
.c-clock__3 {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  font-size: 18px;
}
.c-clock__6 {
  position: absolute;
  bottom: 10px;
  left: calc(50%);
  transform: translateX(-50%);
  font-size: 18px;
}
.c-clock__9 {
  position: absolute;
  top: 50%;
  left: 10px;
  transform: translateY(-50%);
  font-size: 18px;
}

  • 外枠
    • width,height値を決め、border-radius: 50%で丸枠を作っています。

  • 時針
    • 外枠にposition: relativeを仕込んでいるのでabsoluteを使い上下左右中央に配置しています。
    • top: 50%だと時針の高さ分ずれてしまうのでcalcを使い時針の高さ分引いてます。

  • 分針
    • 分針も時針と同じです。

  • 時間文字 ここはwidth、heightを使ってないのでcalc(50% - ○px)とかして上下左右中央に配置できません。 なのでtop: 50%;を設定し、transform: translateY(-50%)で要素の表示位置を要素の半分の大きさ分、上にずらします。

js


setInterval(() => {
  // 現在時間の取得
  const now = new Date();
  const h = now.getHours();
  const m = now.getMinutes();
  const s = now.getSeconds();

  // 時、分、秒を元に角度を計算
  const degH = h * (360 / 12) + m * (360 / 12 / 60);
  const degM = m * (360 / 60);
  const degS = s * (360 / 60);

  // 各要素を取得
  const elementH = document.querySelector(".c-clock__hour");
  const elementM = document.querySelector(".c-clock__min");
  const elementS = document.querySelector(".c-clock__sec");

  // styleを追加
  elementH.style.transform = `rotate(${degH}deg)`;
  elementM.style.transform = `rotate(${degM}deg)`;
  elementS.style.transform = `rotate(${degS}deg)`;
}, 10);

まず、タイマー処理でよく使われるsetIntervalを使用します。
setInterval関数は一定時間ごとに繰り返し処理を行う関数です。
似たものでsetTimeoutがありますが、こちらは一定時間後に処理を行うだけで繰り返しはしません。


setInterval(関数,時間の指定)という感じで使用します。
上のコードでは10ミリ秒(0.01秒)ごとに処理を繰り返していることになります。


次は中の処理ですが、

現在時間の取得

ここでは現在時間をnew Date();で取得しています。
console.log(new Date())などとすると現在の日付、時刻などが取得できているのがわかると思います。
それぞれ現在の時間、分、秒をget◯◯で取得しています。


時、分、秒を元に角度を計算

上で取得した現在の時間、分、秒を元に針の角度を割り出しています。

  • 時間: 一周は360度なので現在の時間(360/時間)としています。ですがそれだけだとダメなので現在の分(360/時間(12)/分(60))を足しています。
  • 分、秒数: ここそれぞれの現在の分数、秒数*(360 / 60)としています。

要素の取得

document.querySelectorで各クラスを指定し要素を取得しています。


style追加

最後に取得した要素にstyleを追加し、現在時間を元に出した角度を設定します。
transform: rotate${}deg;


これを実行してみるとしっかり時計が動いていると思います。

こんな感じでcssとかjsを使えば割となんでも作れるなと思いました。

ふざけた内容ですがこんな記事も書きました。

https://qiita.com/w-tdon/items/1023e159dafbc0fd960d

終わり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript: 「エラトステネスの篩」を読んで関数にしてみた

とくに必要というわけではないのですが、最近、素数づいてるので書きます。

「エラトステネスの篩」の説明の記事を読んで、全然頭に入ってこなくてもやっとしてしまったので。
(記事のせいではないです。だんだん理解力が...)

...困ったときのwikipedia。
エラトステネスの篩

アルゴリズム
(中略)
ステップ 1
探索リストに2からxまでの整数を昇順で入れる。
ステップ 2
探索リストの先頭の数を素数リストに移動し、その倍数を探索リストから篩い落とす。
ステップ 3
上記の篩い落とし操作を探索リストの先頭値がxの平方根に達するまで行う。
ステップ 4
探索リストに残った数を素数リストに移動して処理終了。

だそうな。

やってみます。
たぶん末尾再帰案件だとあたりをつけました。

const primesInner = primes => sieveds =>
  sieveds[0] > Math.sqrt(sieveds[sieveds.length-1]) ? [...primes, ...sieveds] //ステップ3>>4
  : primesInner( [...primes, sieveds[0]] )(
      sieveds.slice(1).filter( e => e % sieveds[0] != 0 )
    )  //ステップ2

const primesUpTo = n =>
  primesInner( [] )( [ ...Array(n + 1).keys() ].slice(2) ) //ステップ1

primesUpTo(100)
/*
[
   2,  3,  5,  7, 11, 13, 17, 19,
  23, 29, 31, 37, 41, 43, 47, 53,
  59, 61, 67, 71, 73, 79, 83, 89,
  97
]
*/

ああ、こういうことね。これだったらわかるわ...

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

正式リリース前に総予習!! Vue3の変更点まとめ

8月上旬に正式リリース予定とされているVue3の変更点をいち早く理解できるように概要をまとめてみました。それぞれの項目ごとにvuejs/rfc又はVue3 Documentへのリンクを貼っているので索引的に使ってもらえると嬉しいです。

この記事は以下バージョン時点の情報です。

Composition APIの追加

おそらく一番大きな目玉となる変更はこちら。Composition APIという新しいAPIが追加されます(PluginでVue2系でも使用可能です)。
Composition APIはコンポーネントのロジックの柔軟な再構成を可能にする関数ベースのAPI群です。
なお、Vue2系のOptions APIのサポートも継続されるので、Vue2系からのVue3へのバージョンアップ時にComposition APIに書き換える必要はありません。

<!-- Vue3 Composition API -->
<template>
  <form>
    <input type="text" v-model="formState.name" />
    <input type="text" v-model="formState.value" />
    <p>{{ contentLength }}</p>
    <button @click="submit" type="submit">submit</button>
  </form>
</template>

<script lang="ts">
import { defineComponent, computed, ref, onMounted, reactive } from "vue";

export default defineComponent({
  props: {
    maxContentLength: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    // reactive data
    const formState = reactive({
      name: '',
      content: ''
    })

    // computed
    const contentLength = computed(() => `${formState.content.length} / ${props.maxContentLength}`)

    // emit
    const submit = () => context.emit('submit', formState)

    // lifecycle hook
    onMounted(() => {
      // ....
    })

    return {
      formState,
      contentLength,
      submit
    };
  }
});
</script>

Composition APIについてはこちらの記事でより詳細にまとめています。

先取りVue 3.x !! Composition API を試してみる - Qiita
Vue Composition APIで使えるリアクティブ関連のAPI一覧 - Qiita

Teleportの追加

Teleportは定義したコンポーネントが属するDOMツリーとは別の場所に、まるでテレポートしたかのようにコンポーネントを移動できる機能です。Vue2系でもサードパーティのプラグインLinusBorg/portal-vueで実現されていました。

以下のようにモーダル表示をハンドルするコンポーネントで<teleport>を使うと、toで指定したDOM要素に内部のコンポーネントを移動できます。

<template>
  <div class="container">
    <button @click="toggleModal">toggle modal</button>
    <teleport to="#teleport-target">
      <MyModal v-if="isVisible"/>
    </teleport>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";

export default defineComponent({
  setup() {
    const isVisible = ref(false);

    const toggleModal = () => {
      isVisible.value = !isVisible.value; };
    return {
      isVisible,
      toggleModal
    };
  }
});
</script>

toで指定できるDOM要素は自身のVueインスタンスをマウントしたDOM要素以外も指定できます。

<html lang="ja">
<body>
  <div id="app"></div> <!-- VueがマウントされるDOM -->
  <div id="teleport-target"></div> <!-- teleportで指定されているDOM。ここにMyModalが表示される-->
  <script src="/dist/main.js"></script>
</body>
</html>

teleportを利用すると、いままでCSSのz-indexで調整していたDOMの重なり順制御を、宣言的に制御できるようになりz-indexの指定に悩まされることはなくなります。
Vue3を入れたらすぐに使いたいと思える実用的な機能ですね。

こちらの記事でも詳細をまとめています。
Vue.js 3.0 の新機能を試す。 〜 Teleport 編〜 - Qiita

Fragmentsの追加

FragmentsはVue2系では実現できなかったmulti-root nodeのコンポーネントを可能にするものです。
Vue2系ではコンポーネントのroot要素は必ず1つという制約がありました。

<template>
  <div>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </div>
</template>

Vue3ではFragmentsのおかげでその制約がなくなり、root要素に複数の要素を記載できます。冗長なdivでのラップなどが不要になります。簡潔で良いですね。

<template>
  <header>...</header>
  <main>...</main>
  <footer>...</footer>
</template>

ただ、注意点としてコンポーネントに直接Class指定をしていると、今まで自動的にroot要素にClassを当てられたのですが、それがfragmentsの場合は明示的な指定が必要になるというのがあります。

Suspenseの追加(実験的)

Suspenseは非同期処理が解決されるまでフォールバックコンテンツ(例えばLoading中アイコン)を表示してくれる特別なコンポーネントです。いままで、v-if="loading === true" などの状態変数を使って制御していたものを、状態変数を使わずに簡潔に書くことができます。

Suspenseはまだ実験的な機能で、Vue3.0の段階では仕様が確定しておらず今後変更が入ることも考えられます。Vue 3.1での正式リリースを見越しているとのことです。

<template>
  <Suspense>
    <template #default>
      <AsyncComponents/> <!-- 非同期処理を実行するコンポーネント -->
    </template>
    <template #fallback>
      loading...
    </template>
  </Suspense>
</template>

Suspenseの詳細はこちらにまとめています。
Vue.js 3.0 の新機能を試す。 〜 Suspense 編〜 - Qiita

v-modelの仕様変更

v-modelの機能が拡張され、ひとつの要素に複数のv-modelの設定が可能になります。
Vue2系のv-bind.syncで実現していたようなことがv-modelで実現できるようになるイメージですね。この機能によってv-bind.syncは代替されるので利用できなくなります。

以下v-modelの複数バインドの例です。
v-model:xxxxのxxxのところで明示的にバインドするプロパティを指定しています。

<!-- 親コンポーネント -->
<template>
  <UserForm
   v-model:name="name"
   v-model:message="message"
  />
</template>
<!-- UserFormコンポーネント -->
<template>
  <form>
   <label>name</label>
   <input 
    type="text"
    @input="$emit('update:name', $event.target.value)"
   >
   <label>message</label>
   <input 
    type="text"
    @input="$emit('update:message', $event.target.value)"
   >
  </form>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    name: {
      type: String,
      default: ''
    },
    age: {
      type: String,
      default: ''
    }
  },
  setup() { return {} }
})
</script>

また、modifiersの機能が拡張され、.lazy, .number, trimのデフォルトのmodifiers以外に独自に,modifiersを定義できるようになりました。
以下はcapitalizeというmodifiersを設定している例です。v-model:name.capitalize=とすることで入力値にcapitalizeを実行しています。

<!-- 親コンポーネント -->
<template>
  <form>
    <MyName  v-model:name.capitalize="form.name"/>
    <!-- ... -->
  </form>
</template>
<!-- MyNameコンポーネント -->
<template>
  <input
    :value="name"
    @input="updateName"
    type="text"
    name="name"
  />
</template>

<script>
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    name: {
      type: String,
      default: ''
    },
    nameModifiers: {
      default: () => ({})
    }
  },
  setup (props, { emit }) {
    const updateName = event => {
      let val = event.target.value
      if (props.nameModifiers.capitalize) {
        val = val.charAt(0).toUpperCase() + val.slice(1)
      }

      emit('update:name', val)
    }

    return {
      updateName
    }
  }
}
</script>

scoped CSSの仕様変更

scoped CSSで使える擬似クラスの仕様変更・機能追加が行われます。
まず1つ目が::v-deep()でこれは、今まで/deep/として設定していた、子コンポーネントにスタイルを適用するための擬似クラスです。
/deep/の記法がDEPRECATEDとなり、新たに::v-deep()が追加されています。

::v-deep(.foo) {}
/* コンパイル後 */
[v-data-xxxxxxx] .foo {}

2つ目が、::v-slotted()で、これはslotで受け取った親コンポーネントの要素にスタイルを適用するためのものです。Vue3からデフォルトではslotで受け取った要素は、子コンポーネントのスタイルが適用されなくなるため、こちらが追加されました。

::v-slotted(.foo) {}
/* コンパイル後 */
.foo[v-data-xxxxxxx-s] {}

最後が、::v-global()で、これはscoped CSSの中でグローバルなスタイルの定義を可能とするものです。この擬似要素を設定したクラスには[v-data-xxxx]が付与されないため、Scopedではなくグローバルに適応されます。

::v-global(.foo) {}
.foo {}

$attrsの仕様変更

$attrsの機能が拡張され、今まで$listenersで参照していたネイティブイベントや別管理であったclass、styleも全て包括して$attrsから取得できるようになりました。

<MyButton 
  @click="handleClick" 
  @custom="handleCustom" 
  v-model="value"
  type="button"
  class="btn"
/>
// MyButton.vue
$attrs: {
  class: 'btn'
  type: 'button',
  onClick: handleClick,
  onCustom: handleCustom,
  'onUpdate:modelValue': () => { value = payload },
}

そのため、$listenersはDEPRECATEDとなります。(実行時に警告がでます)
$listenersを使って透過的なラッパーコンポーネントを作っていた場合は、$listenersを削除し$attrsへの書き換えが必要です。

<!-- Vue2系 -->
<input v-bind="$attrs" v-on="$liseners" />
<!-- Vue3 -->
<input v-bind="$attrs" />

Global APIの仕様変更

Vueの初期化処理が変わります。createAppでインスタンスを生成し、そのインスタンススコープでusemixinなどが適応されるようになります。
これによってテストケースでのグローバル設定の汚染を防いだり、同一ファイル内で別設定のVueインスタンスの初期化が容易になります。

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App) // インスタンスを生成

app.config.isCustomElement = tag => tag.startsWith('app-')
app.use(/* ... */) // インスタンススコープで設定される
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.config.globalProperties.customProperty = () => {}

app.mount(App, '#app')

filterの廃止

filterは、パイプ演算子|を使って関数適応をlinuxの標準入出力のパイプラインするものですがJavaScriptにはない独自構文で学習コストが増加する、構文解析を複雑にするという理由で削除されます。

filterの処理は通常の関数適応で代替できます。

<!-- filter形式 -->
<p>{{ msg | uppercase | reverse }}</p>

<!-- 通常の関数適応形式 -->
<p>{{ reverse(uppercase(msg)) }}</p>

他の代替方法についてはrfcs/0015-remove-filters.md#alternativesをご覧ください。

Event Emitter系のAPIの廃止

Event Emitter系のAPI($on, $off, $once)が削除されます。
グローバルなイベント管理としてEvent Emitterを仕様している場合は書き換えが必要です。
Event管理の代替にはMittなどの別のEvent Emitterライブラリの利用が推奨されています。

Functional Componentの廃止

Functional Componentはdata等の状態を持たない代わりにレンダリングパフォーマンスの大幅な改善が行えるコンポーネントです。
Vue3ではFunctional Componentを作る際に使用するfunctional: trueのオプションや、<template functional>が削除されます。

Vue3では、通常のコンポーネントとFunctional Componentの性能差は大幅に縮小され、ほとんどのユースケースでは取るに足らないものとなったそうです。

SFC上でfunctionalを使用している場合は、functionalの属性を削除し、attrs、listnersの参照方法の修正が必要です。

<!-- Vue2 functional component -->
<template functional>
  <component
    :is="`h${props.level}`"
    v-bind="attrs"
    v-on="listeners"
  />
</template>

<script>
export default {
  props: ['level']
}
</script>
<!-- Vue3 -->
<template> <!-- functionalを削除 -->
  <component
    v-bind:is="`h${props.level}`"
    v-bind="$attrs" <!-- attrs及びlistnersは$attrsにまとめられる  -->
  />
</template>

<script>
export default {
  props: ['level']
}
</script>

終わりに

以上「正式リリース前に総予習!! Vue3の変更点まとめ」でした。
色々ワクワクするような新機能が追加されていてVue3のリリースが待ち通しいですね。
他にも諸々細かい点が変わってるのでより詳細な変更はvuejs/rfcをご確認ください。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ServiceNowからTeamsに通知を飛ばす

概要

ServiceNowではIntegrationHub にSlack Spoke, Microsoft Teams Spoke その他メッセージ送信するアクションがありますが、
別のサブスクリプションが必要なので、RESTメッセージを使用して実装できないか調べてみました。

プラットフォーム

Paris

サンプルケース

変更要求のステータスが実装になるとTeamsに通知するというケースを想定
変更要求の更新をトリガーでビジネスルールでTeamsのWebhookにメッセージを送信します。

手順

Webhookの設定

Webhookの設定は他の記事を参考にして
Microsoft Teams API (Incoming Webhook) で投稿

エンドポイントをコピーしておく

RESTメッセージの設定

System Web Services > Outbound > REST Message から[New] ボタンを押してREST Messageを登録

コピーしたエンドポイントをここにペースト

登録後RESTメッセージ関数(HTTP Methods)を作成
今回はDefault GETを編集しました。

HTTPメソッドをPOSTにして更新

テスト送信

Script - Backgroundで実行してみます。

bg_script.js
var restMessage = new sn_ws.RESTMessageV2("Teams通知", "メッセージ送信");
var message = "メッセージテスト"; 
var body = createBody(message);
restMessage.setRequestBody(body);
var response = restMessage.executeAsync();

 function createBody(message) {
    var body = {
        type : "message",
        text : message
    };
  return new JSON().encode(body);
 }

飛びました

ビジネスルールを設定

変更要求の更新をトリガーにしてメッセージを送信するビジネスルールを作成
実行タイミングは非同期にしています。
ChangesやChangesToは変更前が無いから非同期では使えないと思っていたのですが、コンディションビルダーで使用する場合には使えるらしいです。知らなかった。
https://docs.servicenow.com/bundle/paris-application-development/page/script/business-rules/reference/r_HowBusinessRulesWork.html

コードはこんな感じで書いてみる

send_change_implementation.js
(function executeRule(current, previous /*null when async*/) {
    var restMessage = new sn_ws.RESTMessageV2("Teams通知", "メッセージ送信");
    var message = createMessage(current);
    var body = createBody(current, message);
    restMessage.setRequestBody(body);
    var response = restMessage.executeAsync();
})(current, previous);

function createMessage(current) {
    var url = gs.getProperty('glide.servlet.uri')+'/change_request.do?sys_id=' + current.sys_id;
    var message = '【お知らせ】以下の変更を実装します!<br/>' +
            '番号:<a href="' + url + '">' + current.number + '</a><br/>';
    message += '作業名: ' + current.short_description + '<br/>';
    message += '終了予定時刻: ' + current.end_date.getDisplayValue();

    return message;
}

function createBody(current, message) {
    var body = {
        type : "message",
        text : message
    };
    return new JSON().encode(body);
}

結果がこちら

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

console.logでJSONから特定の要素を取り出す方法

JavascriptでJSONから特定の要素を取り出す際の考え方が配列のときと少し異なるのでまとめました。

JSONとは

  • JavaScript Object Notationの略。直訳すると「Javascriptオブジェクト記法」ということになる。JSONにおけるJavascriptオブジェクトとは基本的には、{}(オブジェクト)と[](配列)を組み合わせてデータ構造を表現したものをJSONとして扱うことができる。

→つまり、JSONとは、{}(オブジェクト)と[](配列)を組み合わせてデータ構造のこと。

JSONの特定の要素の取り出し方

example.tsx
const messageArrayContainer: any[] = [{
    "text": ["Suzuki", "Yamada", "Miyazaki" ]
    "user": {"_id": 1, "avatar": "", "name": ""}
  }];

console.log('データ' + JSON.stringify(messageArrayContainer, replacer));
console.log('userデータ' + JSON.stringify(messageArrayContainer[0].user, replacer) );
//データ
[{
    "text": ["Suzuki", "Yamada", "Miyazaki" ]
    "user": {"_id": 1, "avatar": "", "name": ""}
  }]

//userデータ
{"_id": 1, "avatar": "", "name": ""}

ここで、注意なのが、配列と同じように考えると、userデータのみを取り出したいときに、下記のように書きたくなるがこれだとundefinedが表示される。

example1.tsx
console.log('userデータ' + JSON.stringify(messageArrayContainer[0].user, replacer) );

//結果は,undefinedになる

JSONは大きな一つの要素と考え、

example2.tsx
console.log('userデータ' + JSON.stringify(messageArrayContainer[0].user, replacer) );

//出力: userデータ{"_id": 1, "avatar": "", "name": ""}

と書く。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む