- 投稿日:2019-10-28T23:56:24+09:00
WebComponents だけでアプリの骨格を作ってみる
はじめに
WebComponents、何がいいかというとブラウザでネイティブに対応してるとこですね。
そろそろ本家、3rdパーティーともライブラリが充実してきて、Vue とか React とかのフレームワークを使わずに WebComponents だけでいけそうな感じになってきたので、とりあえず下のようなアプリの骨格を作って検証してみます。
オフィシャルの material.io の GitHub にはメジャーな
- material-components-android
- material-components-ios
- material-components-web
- material-components-flutter
の他に
ってのがあります(名前が非常にまぎらわしい><)。GUI コンポーネントとして今回これを使わせてもらいます。
また router として、
を使わせてもらいます。
早速作ってみましょう。
準備
node, npm をダウンロードします
https://nodejs.org
この記事は node v12.4.0, npm 6.12.0 で検証していますディレクトリを掘って cd して node のプロジェクトを作成します。
$ mkdir wc $ cd wc $ yarn inites-dev-server をインストールして動かしておきます。
$ npm install -g es-dev-server $ es-dev-server --node-resolve --watch8000 番のポートが使われてなければ
es-dev-server started on http://localhost:8000
と表示されます。ブラウザでここにアクセスしてください。--node-resolve オプションが何故必要かについて知りたい場合は以下を参照してください。
https://github.com/material-components/material-components-web-components/blob/master/README.md
作成
使うコンポーネントを登録
$ yarn add @material/mwc-drawer $ yarn add @material/mwc-icon-button $ yarn add @material/mwc-top-app-bar $ yarn add @vaadin/routerメイン画面に表示する WebComponent を作成
Main.jsclass Main extends HTMLElement { constructor() { super(); this.attachShadow( { mode: 'open' } ).innerHTML = '<div>MAIN</div>' } } customElements.define( 'jp-main', Main )About.jsclass About extends HTMLElement { constructor() { super(); this.attachShadow( { mode: 'open' } ).innerHTML = '<div>ABOUT</div>' } } customElements.define( 'jp-about', About )まとめあげ
index.html<!doctype html> <html lang=zxx> <title>drawer demo</title> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Material+Icons&display=block" rel="stylesheet"> <body> <script type="module"> import '@material/mwc-drawer' import '@material/mwc-top-app-bar' import '@material/mwc-icon-button' import './Main' import './About' import { Router } from '@vaadin/router' class App extends HTMLElement { constructor() { super(); this.attachShadow( { mode: 'open' } ).innerHTML = ` <mwc-drawer hasHeader type="dismissible"> <span slot="title">Drawer Title</span> <span slot="subtitle">subtitle</span> <div> <p>Drawer content</p> <a href="/">Main</a><br /> <a href="/About">About</a><br /> </div> <div slot="appContent"> <mwc-top-app-bar> <mwc-icon-button slot="navigationIcon" icon="menu"></mwc-icon-button> <div slot="title">Title</div> </mwc-top-app-bar> <div id="outlet" /> </div> </mwc-drawer> ` const router = new Router( this.shadowRoot.getElementById( 'outlet' ) ) router.setRoutes( [ { path: '/' , component: 'jp-main' } , { path: '/about' , component: 'jp-about' } ] ) const drawer = this.shadowRoot.querySelector( 'mwc-drawer' ) drawer.parentNode.addEventListener( 'MDCTopAppBar:nav' , _ => drawer.open = !drawer.open ) } } customElements.define( 'jp-app', App ) </script> <jp-app /> </body>勘所
navigationIcon
mwc-top-app-bar の navigationIcon スロットに入れられたボタンが押されると、mwc-drawer の parentNode に対して MDCTopAppBar:nav イベントが送られます。(すみません、ドキュメントが見当たりません><、レポジトリの demos/drawer/のあたりを読んで発見しました)
shadowRoot
WebComponent は constructor の中で attachShadow ってやると、shadowRoot が使えるようになります。プライベートな DOM みたいなものです。これを実際の DOM に connect して表示するようになります。
constructor の中ではまだ実際の DOM にコネクトされていないので、shadowRoot に対して getElement... とか querySelector とか発行して、エレメントをとります。shadowRoot に対して、今回の記事では innerHTML をスタティックテキストでセットしているだけですが、実際にはダイナミックに生成したい場合が多いと思われます。そんなときは polymer の lit-element を使うという選択肢があります。lit-html という HTML テンプレートライブラリをラップしたものです。
古いブラウザのサポート
Edge とか IE11 とかをサポートするにはポリフィルが必要です。詳しくは以下を参照してください。
https://github.com/material-components/material-components-web-components/blob/master/README.md
最後に
shadowRoot を更新する際に既存のエレメントを再利用して描画の高速化を図るようなベースクラスをたぶんそのうち誰かが作ってくれる気がします。もし知っていたら教えてください。
- 投稿日:2019-10-28T23:28:57+09:00
[養老乃瀧ハッカソン2019]ひたすらビールを注文するコースターを作った
目次
- はじめに
- 機能概要
- 実装コード
- 感想と反省点
はじめに
◆飲み会で、周囲の人のグラスが空いていたら、「何か飲まれますか?」と聞いて飲み物を注文せねばならぬ。
◆俺はただ、ビールが飲みたいんだ!飲む物は決まってるんだから注文せずにズッて持ってこいや!って思うこと、ありませんか?
少なくとも、私は常々思ってます。
なので、空いたグラスをドッと置いたらビールがズッと来るデバイスを作れないだろうかと思って、実際に作りました。
また、居酒屋にあると嬉しい(主に私が)ので、養老乃瀧ハッカソン2019で発表してきました。機能概要
3.飲む!
実装コード
nomanomaWay.js'use strict'; // Obniz用定数 var Obniz = require('obniz'); var obniz = new Obniz('yourObnizNumber'); var obniz2 = new Obniz('yourObnizNumber'); var stringWeight; // Obniz関数 obniz.onconnect = async function () { obniz.display.clear(); // ロードセル var hcsr04 = obniz.wired("hx711", { gnd: 0, dout: 1, sck: 2, vcc: 3 }); while (true) { hcsr04.offset = 88815; hcsr04.scale = 88925; var val = await hcsr04.getValueWait(1); stringWeight = Math.abs(roundFloat(val, 4) * 10000); console.log(Math.abs(roundFloat(val, 4) * 10000)); await obniz.wait(10); if (Number.isInteger(stringWeight) == false) { hcsr04.powerDown(); obniz.close(); }; } function roundFloat(number, n) { var _pow = Math.pow(10, n); return Math.round(number * _pow) / _pow; } } obniz2.onconnect = async function () { obniz2.display.clear(); // ソレノイド var solenoid = obniz2.wired('Solenoid', { gnd: 0, signal: 1 }); await obniz2.wait(3000); if (obniz.connectionState == 'closed') { solenoid.on(); await obniz2.wait(3000); solenoid.off(); obniz2.close(); } }感想と反省点
実際に作ったとき、これは賞とれるだろ!と思ったのですが、取れませんでした。
原因を自分なりに考えた時、養老乃瀧ハッカソン2019のテーマが「皆が笑顔になる」ことがメインだったようで、それとはちょっと合わなかったのかなと。
また、ほかの作品たちがインパクトありまくりで、印象に残らなかったというのもあったのかなと。ぶっちゃけ自分の作品地味だしただ、結構悔しかったので、リメイクしてリベンジしたいと思ってます。
改善案としては、コースターを光らせたり、なにか音を出したりすることを考えてます。なお、個性的な作品たちの詳細は、以下サイトをチェックだ!
・protopedia
※タグ検索で 'yorohack2019' を入力してね!
- 投稿日:2019-10-28T19:11:38+09:00
ESLint v6.6.0
前 v6.5.0 | 次 (2019/11/23 JST)
ESLint v6.6.0 has been released: https://t.co/oHo5t86A0k
— ESLint (@geteslint) October 25, 2019ESLint
6.6.0がリリースされました。
小さな機能追加とバグ修正が行われています。これまで ESLint は隔週リリースを行ってきましたが、アクティブなメンテナが減少していることから、今後は月間リリースとなります。
質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。
? 本体への機能追加
context.getCwd()各ルールから現在のディレクトリを取得できるようになりました。
例module.exports = { meta: {}, create(context) { console.log(context.getCwd()) //→ /home/a-user/projects/foo return {} }, }この値は基本的に
process.cwd()と同じですが、いくつかの場合に異なる値になります。
CLIEngineオブジェクトを初期化した後にprocess.chdir()関数によって CWD を変更した場合CLIEngineのコンストラクタ オプションとして独自の CWD を指定した場合また、ブラウザ上で実行している場合など、CWD が不明な場合は
undefinedを返します。? 新しいルール
特になし。
? オプションが追加されたルール
no-param-reassign
ignorePropertyModificationsForRegex? #11275
指定した正規表現にマッチする名前の引数について、プロパティの変更を許可するオプションが追加されました。
例/*eslint no-param-reassign: [error, { props: true, ignorePropertyModificationsForRegex: ["^req"] }]*/ //✘BAD function f1(req, res) { res.value = 0 } //✔GOOD function f2(req, res) { req.value = 0 }use-isnan
enforceForIndexOf? #12379
浮動小数点数の仕様により、
NaNとの比較は常にfalseになります。これを報告するuse-isnanルールに、Array#indexOfメソッドも報告するオプションが追加されました。代わりに、Array#findIndexメソッドを利用したり、NaNを特別に処理する新しいメソッドArray#includesを利用したりしましょう。例/*eslint use-isnan: [error, { enforceForIndexOf: true }]*/ //✘BAD var indexOfNaN= myArray.indexOf(NaN) var hasNaN = myArray.indexOf(NaN) >= 0 //✔GOOD var indexOfNaN = myArray.findIndex(Number.isNaN) var hasNaN = myArray.includes(NaN)no-unsafe-negation
enforceForOrderingRelations? #12414
比較演算子の左辺をオペランドとする否定演算子を警告するオプションが追加されました。
例/*eslint no-unsafe-negation: [error, { enforceForOrderingRelations: true }] */ //✘BAD if (! a < b) {} //✔GOOD if (!(a < b)) {}no-extra-parens
enforceForNewInMemberExpressions? #12436
new式に直接プロパティアクセスを繋げているときに、そのnew式を囲む括弧を無視するためのオプションが追加されました。例/*eslint no-extra-parens: [error, all, { enforceForNewInMemberExpressions: false }] */ //✔GOOD var obj = (new Foo()).prop;✒️
eslint --fixをサポートしたルール特になし。
⚠️ 非推奨になったルール
特になし。




