20190226のvue.jsに関する記事は8件です。

Vue Cli 3で作ったコンポーネントライブラリをnpmで公開する

自己紹介


@coppieee
https://coppieee.com
フリーランスプログラマ
Vue.js、TypeScript、Serverless、Cordovaとかやってます。


Vue.js コンポーネントライブラリを作成しました

Vue.jsでMaterial DesignしたくてVuetifyやVue Materialとかライブラリを触ってみたけど、
CSSなどいろいろカスタマイズし辛い。
なのでMaterial Designの勉強も兼ねて、Material Designの自作ライブラリを作りnpmに公開しました。
npm公開作業は結構簡単にできたのでnpm publishの方法を共有します。


npmで公開したもの

Vuterial

Material Designするための Vue.js コンポーネントライブラリ。
Materail Conponents for Webを使って実装してる。

https://github.com/coppieee/vuterial
https://coppieee.github.io/vuterial/


サンプル(ドキュメントページ)


コンポーネントをnpm publish して公開する手順

  • Vue CLI 3でプロジェクトを作成
  • build設定
  • package.json設定
  • npmjsにサインアップ
  • npm publish

Vue CLI 3でプロジェクトを作成

ライブラリを作成する場合もWebアプリと作るのと同様にVue CLIから作成します。

$ npm i -g @vue/cli
$ vue create your-library-name

特にライブラリ用に特殊な設定は必要ないので自分の好きなように設定しよう。
ライブラリ名は名前が被ってないかnpmjs.comでチェックしておきましょう。


Build設定

ライブラリのビルドはvue-cli-serviceにライブラリ生成用のビルドオプションがあるのでそれを使う。

$ vue-cli-service build --target lib --name your-library-name ./lib-main.js

それをpackage.jsonscriptsbuild-bundleなど適当な名前で設定しておくといいでしょう。

package.json
{
  "scripts":[
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build-bundle": "vue-cli-service build --target lib --name your-library-name ./src/lib-main.js",
    ...
  ]
}

Build結果

$ npm run build-bundle

./distフォルダに以下のファイルが出力される

./dist
your-library-name.common.js
your-library-name.common.js.map
your-library-name.css
your-library-name.umd.js
your-library-name.umd.js.map
your-library-name.umd.min.js
your-library-name.umd.min.js.map

jsとcssを生成してくれる。
WebPackなどで使う場合はcommon.js、ブラウザで直接読み込む場合はumd.jsを使うことになる。
ライブラリの生成まで一つのコマンドでしてくれるVue CLI 3ってすげー。


ライブラリの実装例

今回はVue プラグインとして使う設定をしている。
ライブラリ使用者はVue.use(libraryName)の形式で使うことになる。以下一例。

lib-main.js
import { mdcChip } from './components/mdc-chip.vue'
import { mdcCard } from './components/mdc-card.vue'
import { mdcButton } from './components/mdc-button.vue'
// ...
export default const YourLibraryName = {
  install(Vue, options){
    const components = {
      mdcButton, // <mdc-button/> として使える
      mdcCard, // <mdc-card/> として使える
      // ...
    }
    for(const [name,c] of Object.entries(components)){
        Vue.component(name,c)
    }
  },
} 

package.jsonの設定

package.json
{
  "name": "your-library-name",
  "version": "0.1.0",
  "main":"dist/your-library-name.common.js", // エントリーポイント
  "unpkg": "./dist/your-library-name.umd.min.js", // CDN用(オプション)
  "jsdelivr": "./dist/your-library-name.umd.min.js", //CDN用(オプション)
  "typings":"dist/types/index.d.ts", //typescript用型ファイル(オプション)
  "license": "MIT",
  "author": "your name",
  "files": [
    "dist" // npm publish 対象のフォルダ
  ],
  "dependencies": {}, // distのみ公開の場合はdependenciesの中は空でOK
  "peerDependencies": { // 依存しているライブラリ(オプション)
    "vue": "^2.6.6",
    "vue-router": "^3.0.2"
  },
  "private": false,
  ...
}

npm publishに必要な設定はmainにエントリーポイントのパス設定と、filesでnpm にアップする対象を設定する。
privateをfalseに。
dependenciesにはdistだけを公開する場合は何も書かなくていい。
必要最低限の設定はそれだけであとはオプション。

ちなみに以下のファイルは、filesに指定しなくても自動的にアップされる。

  • package.json
  • README
  • CHANGELOG
  • LICENSE / LICENCE

unpkgとjsdelivrはCDN配布用で、設定するとそれぞれ
https://unpkg.com/your-library-name@latest
https://cdn.jsdelivr.net/npm/your-library-name@latest
というURLでjsファイルにアクセスできるようになる。
htmlのscriptタグのsrcで直接読み込む方式だ。

他にもいろいろ設定があるけど、githubに公開されてるvueとかvuetifyとかのpackage.jsonを見てみると参考になる。


npm login

ビルドの設定が終わったら次はいよいよnpmに公開する作業だ。
npm用のアカウントを作成してから、コンソールでログインする。

npm サインアップ

https://www.npmjs.com/signup

npm login

$ npm login

npm publish

$ npm run build-bundle
$ npm publish

npm 公開完了

https://www.npmjs.com/package/your-package-nameのようなURLで公開確認できる。

https://www.npmjs.com/package/vuterial


npm install example

npm に公開できたらプロジェクトを作成してnpm installしてみよう。

$ vue create my-project
$ cd vmy-project
$ npm i your-library-name

ライブラリをimport

ライブラリをimportしてVue.use()で設定する。
また、cssも使う場合は別途import。

main.js
import Vue from 'vue'
import YourLibraryName from 'your-library-name'
import 'your-library-name/dist/your-library-name.css'
Vue.use(YourLibraryName)

 まとめ

Vue コンポーネントをnpmに公開する場合もVue CLI 3を使うと簡単。


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

Re:ゼロから始めるポートフォリオ開発【Vue.js】

概要

Web初心者がVue.jsでポートフォリオを作ってみた
2019/2/26 レスポンシブ対応してないので注意

準備

前回書いた記事を参照

作成物

ポートフォリオサイト
github

まずコンポーネントを作ろう

とりあえず全ページ共通で使用するものをコンポーネントとして用意すればいいっしょ?
という軽い気持ちで作成。

ヘッダー

Header.vue
<template>
  <div>
    <header class="header">
      <router-link to="/">Top</router-link>
      <router-link to="/about">About</router-link>
      <router-link to="/career">Career</router-link>
      <router-link to="/portfolio">Portfolio</router-link>
      <router-link to="/contact">Contact</router-link>
    </header>
  </div>
</template>

ページタイトル(画面毎に文言が変わるためpropsを設定)

Pagetitle.vue
<template>
  <div class="pagetitle">
    <p> {{pagetitle}} </p>
  </div>
</template>

<script>
export default{
  name:'pagetitle',
  props:{
    pagetitle:{
      type:String,
      default:''
    }
  }
}
</script>

ヘッダーは画面によって文言やデザインが変わる必要は無いのでApp.vueに記載

App.vue
<template>
  <div id="app">
    <Header></Header>
    <router-view/>
  </div>
</template>

<script>
import Header from '@/components/Header'

export default{
  name:'header',
  components:{
    Header
  }
}
</script>

ページの作成

HTMLとCSSでページを作成する。
作成したページタイトルコンポーネントに引数を入れて呼び出す。

トップ画面

Top.vue
<template>
  <div class="top">
    <Pagetitle pagetitle='Top'></Pagetitle>
    <p id="text">Doragon's Portfolio</p>
  </div>
</template>

<script>
import Pagetitle from '@/components/Pagetitle.vue'

export default{
  name:'top',
  components:{
    Pagetitle
  }
}
</script>

Router

作成したページをRouterに設定。

router.js
import Vue from 'vue'
import Router from 'vue-router'
import Top from './pages/Top.vue'
import About from './pages/About.vue'
import Career from './pages/Career.vue'
import Contact from './pages/Contact.vue'
import Portfolio from './pages/Portfolio.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'top',
      component: Top
    },
    {
      path: '/about',
      name: 'about',
      component: About
    },
    {
      path: '/career',
      name: 'career',
      component: Career
    },
    {
      path: '/portfolio',
      name: 'portfolio',
      component: Portfolio
    },
    {
      path: '/contact',
      name: 'contact',
      component: Contact
    }
  ]
})

main.jsにrouterの宣言を忘れずに。

main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

作成したポートフォリオを公開する

今回はgithub pagesにデプロイする。
ソースコードを公開する代わりに無料でwebページを公開してくれる優しいやつ。

vue.config.jsをディレクトリ直下に作成
このままbuildすると/dist直下にビルドファイルが作成されてしまう。
github pagesでは/docs直下のものが公開対象となるため設定を変更する。

vue.config.js
module.exports = {
  baseUrl: process.env.NODE_ENV === 'production'
    ? '/portfolio/'
    : '/',
  outputDir: 'docs',
};

コマンドラインでビルドを行う

$npm run build

github
/docs直下にビルドされたファイルが作成された事を確認した後、masterにpush。
githubのsettingを以下のようにする。
スクリーンショット 2019-02-26 23.28.15.png
反映まで少し時間がかかるので注意
せっかちな人は以下の記事を参考にしてください。
https://qiita.com/shge/items/ac20f45c9e8e0b4f33cc

一言

レスポンシブ対応がまだ出来ていないので後々やります・・・。
SASSも使いたかったけど、全く使っていない・・・。
HTMLとCSSとJSはまだまだ初心者レベルなので修行が必要だと痛感した。
Node.jsも勉強してwebに強くなりたい。

参考文献

https://qiita.com/plus_kyoto/items/a01578b782f17f573510
https://qiita.com/shge/items/ac20f45c9e8e0b4f33cc

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

vue.js 超超超初心者向け用語とかmemo

初心者の自分がvueをやろうとして初心者向けの本を読んでも分からない単語でつまづくことがあったので、自分の経験を踏まえて分からなかった箇所をメモしていく。

Vue.jsとは

Vue.js:https://jp.vuejs.org/v2/guide/
双方向データバインディング(リアクティブ)な設計で実装する、MVVM(Model-View-ViewModel)モデルを起用したjsフレームワークです。
・大規模開発
・アプリ開発
・SPA
等複雑なページを効率良く、煩雑にならないように構築する手助けをしてくれます。

MVVMとは

設計思想のひとつ。
他にはMVC等がある。
(中級者以上向けだと思うので、初心者の段階ではふんわりと、設計の概念と思っていれば良いかと)

基本フロー

image_vue.jpg

1. ページにVue.js本体を読み込む

vue.js本体を読み込むとVueオブジェクトが生成される(グローバル変数Vueが生成される)。

2. jsファイルにVueインスタンスを記述する(DOMをマウントする)

指定したhtml要素に対応するインスタンスを生成する。
インスタンスはこんな感じでnew Vueで作成するやつ↓

new Vue({
  el: 'html element',
  data: {
  },
  method(){
  },
})

↑のhtml elementの箇所がvueで操作する範囲になります。
※vue操作はデータバインディングで使う範囲なので、それ以外は普通のノーマルなjsでDOMを操作します。
Vueインスタンスについて:https://jp.vuejs.org/v2/guide/instance.html

3. Vueインスタンスにオプションを記述する

指定したhtml要素内でvue.jsを操作できるようになります。
option.jpg
オプションの種類:https://jp.vuejs.org/v2/api/#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-%E3%83%87%E3%83%BC%E3%82%BF

4. コンポーネントやmixinや色んな技術で拡張していく

用語

用語 説明
グローバル変数Vue Vue.js本体を読み込んだときに生成されるオブジェクト。
Vueインスタンス Vue.jsで構築するに当たってまず最初に生成するコンストラクタ。
コンストラクタ オブジェクトを生成するための関数。(例 new Vueで作ったVueインスタンス
オプションオブジェクト Vueインストラクタを生成するときに指定するオプション。
コンポーネント 再分化したモジュール郡。再利用できるモジュールにそれぞれ機能を分けて管理することで、プロジェクト内の見通しと開発効率を上げる。
Mastache {{}}←コレ。Vue.jsで使用するテンプレート構文です。データをMastacheで囲むとテキストとして展開されます。
ディレクティブ v-show、v-if、v-on、...等、v-から始まるデータバインディングをするための記述。
プリコンパイル 事前にブラウザが取り込みやすいようにjsのコンパイルをしておくのでパフォーマンスが良い。
JustInTimeコンパイル(JIT) webページを初期表示するときに、ブラウザ側でjsをコンパイルするのでプリコンパイルより反応が遅い。
単一ファイルコンポーネント SFC(single file component)と省略される。template、script、cssをひとつのファイルにまとめた記述方法。

その他メモ

コンポーネント

記述方法としては2パターンある。
・Vueオブジェクトを拡張してグローバルに登録する記述方法
・オブジェクトを作成してvueインスタンスに登録する方法

Vueオブジェクトを拡張してグローバルに登録する方法

参照:https://jp.vuejs.org/v2/guide/render-function.html#%E9%96%A2%E6%95%B0%E5%9E%8B%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

Vue.component('my-component', {
  // オプション
})
オブジェクトを生成してvueインスタンスに登録する方法
//コンポーネントオブジェクト
var component = {
  //オプション
}
//↑このコンポーネントオブジェクトを↓vueインスタンスに登録する
new Vue({
  components:{
    'component':Component
  }
});

気づいたことがあったら追記していきます

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

Vue.js 超超超初心者向け用語とかmemo

初心者の自分がvueをやろうとして初心者向けの本を読んでも分からない単語でつまづくことがあったので、自分の経験を踏まえて分からなかった箇所をメモしていく。

Vue.jsとは

Vue.js:https://jp.vuejs.org/v2/guide/
双方向データバインディング(リアクティブ)な設計で実装する、MVVM(Model-View-ViewModel)モデルを起用したjsフレームワークです。
・大規模開発
・アプリ開発
・SPA
等複雑なページを効率良く、煩雑にならないように構築する手助けをしてくれます。

MVVMとは

設計思想のひとつ。
他にはMVC等がある。
(中級者以上向けだと思うので、初心者の段階ではふんわりと、設計の概念と思っていれば良いかと)

基本フロー

image_vue.jpg

1. ページにVue.js本体を読み込む

vue.js本体を読み込むとVueオブジェクトが生成される(グローバル変数Vueが生成される)。

2. jsファイルにVueインスタンスを記述する(DOMをマウントする)

指定したhtml要素に対応するインスタンスを生成する。
インスタンスはこんな感じでnew Vueで作成するやつ↓

new Vue({
  el: 'html element',
  data: {
  },
  method(){
  },
})

↑のhtml elementの箇所がvueで操作する範囲になります。
※vue操作はデータバインディングで使う範囲なので、それ以外は普通のノーマルなjsでDOMを操作します。
Vueインスタンスについて:https://jp.vuejs.org/v2/guide/instance.html

3. Vueインスタンスにオプションを記述する

指定したhtml要素内でvue.jsを操作できるようになります。
option.jpg
オプションの種類:https://jp.vuejs.org/v2/api/#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-%E3%83%87%E3%83%BC%E3%82%BF

4. コンポーネントやmixinや色んな技術で拡張していく

用語

用語 説明
グローバル変数Vue Vue.js本体を読み込んだときに生成されるオブジェクト。
Vueインスタンス Vue.jsで構築するに当たってまず最初に生成するコンストラクタ。
コンストラクタ オブジェクトを生成するための関数。(例 new Vueで作ったVueインスタンス
オプションオブジェクト Vueインストラクタを生成するときに指定するオプション。
コンポーネント 再分化したモジュール郡。再利用できるモジュールにそれぞれ機能を分けて管理することで、プロジェクト内の見通しと開発効率を上げる。
Mastache {{}}←コレ。Vue.jsで使用するテンプレート構文です。データをMastacheで囲むとテキストとして展開されます。
ディレクティブ v-show、v-if、v-on、...等、v-から始まるデータバインディングをするための記述。
プリコンパイル 事前にブラウザが取り込みやすいようにjsのコンパイルをしておくのでパフォーマンスが良い。
JustInTimeコンパイル(JIT) webページを初期表示するときに、ブラウザ側でjsをコンパイルするのでプリコンパイルより反応が遅い。
単一ファイルコンポーネント SFC(single file component)と省略される。template、script、cssをひとつのファイルにまとめた記述方法。

その他メモ

コンポーネント

記述方法としては2パターンある。
・Vueオブジェクトを拡張してグローバルに登録する記述方法
・オブジェクトを作成してvueインスタンスに登録する方法

Vueオブジェクトを拡張してグローバルに登録する方法

参照:https://jp.vuejs.org/v2/guide/render-function.html#%E9%96%A2%E6%95%B0%E5%9E%8B%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

Vue.component('my-component', {
  // オプション
})
オブジェクトを生成してvueインスタンスに登録する方法
//コンポーネントオブジェクト
var component = {
  //オプション
}
//↑このコンポーネントオブジェクトを↓vueインスタンスに登録する
new Vue({
  components:{
    'component':Component
  }
});

気づいたことがあったら追記していきます

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

Nuxt.js/Vue.jsでJSONPを取得する

前準備

プロジェクトにvue-jsonpをインストールします。
vue-jsonp - npm

yarn add vue-jsonp

pluginsの設定、およびnuxt.config.jsでの設定

~/plugins/vue-jsonp.js
import Vue from 'vue';
import VueJsonp from 'vue-jsonp';

Vue.use(VueJsonp);
nuxt.config.js
省略
  plugins: ['~/plugins/vue-jsonp'],
省略

この設定をし、再度ローカルサーバを立ち上げるコマンドを打てば this.$jsonp が使えるようになります。

static配下のローカルjsonpにアクセスするサンプルコード

$jsonpの第二引数のObjectのcallbackNameにはjsonp側の関数名を指定すればOKです。
他に渡すパラメータが必要な場合は第二引数のObjectに一緒に入れちゃいましょう。
一緒に入れてあげるとリクエストURLにクエリパラメータが自動で付いてアクセスしてくれます。

コンポーネント
 async mounted() {
    const url = '/jsonp/test.js';
    const json = await this.$jsonp(url, {
      callbackName: 'getData'
    });
    console.log(json);
 }
static/jsonp/test.js
getData({
  data: 'sample'
})

参考リンク

覚え書き Vue.jsでjsonpを使ってみる - Qiita

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

Vue.js のカスタムディレクティブの使い方とフック関数のタイミングを理解する

はじめに

Vue.js(2.6.7)のカスタムディレクティブに関しての備忘録です。

そもそもディレクティブとは?

テンプレートに記述できるv-から始まる属性のこと。

様々なディレクティブが存在し、属性値に応じた DOM 操作ができる。

以下は DOM 操作の例。

  • 要素の表示制御
  • データバインディング
  • イベントリスナのアタッチ

ディレクティブの利用例

以下はv-show(値に応じて要素のstyle.displayプロパティを変更するディレクティブ)の利用例。

<div id="app">
  <h1 v-show="ok">Hello!</h1>
</div>
const vm = new Vue({
  el: '#app',
  data: {
    ok: true
  }
});
// `ok`を`false`にすれば、`<h1 v-show="ok">Hello!</h1>`は非表示になる。
// vm.$data.ok = false;

See the Pen Vue.js v-show by soarflat (@soarflat) on CodePen.

dataoktrueの場合、<h1>Hello!</h1>は表示され、falseの場合、<h1 style="display:none;">Hello!</h1>となり表示されない。

この他にも様々なディレクティブが存在する。詳細は公式ドキュメントを参照。

ディレクティブ

カスタムディレクティブとは?

自作したディレクティブ、もしくは自作したディレクティブを登録できる機能(仕組み)のこと。

カスタムディレクティブを利用することで、属性の付与もしくは属性値の変化に伴う DOM 操作を定義できる。

なぜカスタムディレクティブを利用するのか(カスタムディレクティブの使い所)

前述の通り、v-showは値に応じてstyle.displayプロパティを変更しているだけなので、この DOM 操作は自前でも定義できる。

しかし、ディレクティブという仕組みを利用することで、それぞれのコンポーネント(Vue インスタンス)に「値に応じてstyle.displayプロパティを変更する DOM 操作」を定義せずとも、共通の DOM 操作が可能になる。

そのため、複数のコンポーネント(Vue インスタンス)で独自の DOM 操作を共通化したい場合、カスタムディレクティブを定義する。

カスタムディレクティブの利用例

以下は、v-focusというカスタムディレクティブを定義する例。

ページを読み込む(Vue インスタンスをマウントする)とinput要素に自動でフォーカスが当たるようにする。

Vue.directive('focus', {
  inserted(el) {
    el.focus();
  }
});

insertedはカスタムディレクティブと紐付いた要素が親 Node に挿入された時に呼ばれるフック関数。引数elには親 Node に挿入された要素が渡される。

カスタムディレクティブと要素を紐付けるためには、以下のように定義したv-focusを付与する。

<input v-focus>

今回の場合、このinput要素が親 Node(今回の場合はbody要素)に挿入された時にinsertedが呼び出され、引数elに挿入されたinput要素が渡される。

実際に動作するコードは以下の通り。

<input id="input" v-focus>
Vue.directive('focus', {
  // `el`に`input`要素が渡されるので、それにフォーカスを当てる
  inserted(el) {
    el.focus();
  }
});

new Vue({
  el: '#input'
});

See the Pen Vue.js CustomDirective example by soarflat (@soarflat) on CodePen.

ローカルディレクティブに登録する

directivesオプションを利用すれば、コンポーネント毎にカスタムディレクティブを登録できる。

<input id="input" v-focus>
new Vue({
  el: '#input',
  directives: {
    focus: {
      inserted(el) {
        el.focus();
      }
    }
  }
});

フック関数

前述のinsertedを含め、カスタムディレクティブでは以下のフック関数を利用できる。

  • bind: カスタムディレクティブが初めて対象の要素に紐付いた時に1度だけ呼ばれる。
  • inserted: カスタムディレクティブと紐付いた要素が親 Node に挿入された時に呼ばれる。
  • update: 紐付いた要素を抱合しているコンポーネントの VNode が更新される度に呼ばれる(子コンポーネントが更新される前に呼ばれる)。
  • componentUpdated: 紐付いた要素を抱合しているコンポーネントの VNode と子コンポーネントの VNode が更新された時に呼ばれる。
  • unbind: 紐付いた要素からディレクティブが取り除かれた時に呼ばれる。

それぞれのフック関数が呼ばれるタイミングを理解する

以下は全てのフック関数が呼ばれるサンプル。

<div id="app">
  <h1 v-message v-if="message">{{ message }}</h1>
  <button @click="update">update</button>
  <button @click="remove">remove</button>
  <button @click="init">init</button>
</div>
Vue.directive('message', {
  bind(el) {
    console.log('bind');
    console.log('el.parentNode(bind)', el.parentNode);
  },
  inserted(el) {
    console.log('inserted');
    console.log('el.parentNode(inserted)', el.parentNode);
  },
  update(el) {
    console.log('update');
    console.log('el.innerHTML(update)', el.innerHTML);
  },
  componentUpdated(el) {
    console.log('componentUpdated');
    console.log('el.innerHTML(componentUpdated)', el.innerHTML);
  },
  unbind(el) {
    console.log('unbind');
  }
});

new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  },
  methods: {
    update() {
      this.message = 'Hello React!';
    },
    remove() {
      this.message = '';
    },
    init() {
      this.message = 'Hello Vue!';
    }
  }
});

See the Pen Vue.js Hook Functions(Custom Directives) by soarflat (@soarflat) on CodePen.

それぞれのフック関数がどのタイミングで呼ばれるのかは、以下の通り。

  • ページロード時(Vue インスタンスを生成時): bindinserted
  • 「update」ボタンをクリック時: updatecomponentUpdated
  • 「remove」ボタンをクリック時: unbind
  • 「init」ボタンをクリック時(「remove」ボタンをクリックした後): bindinserted

ページロード時(Vue インスタンスを生成時)

bindinsertedが呼ばれて以下がコンソール出力される。

// bind
// el.parentNode(bind) null
// inserted
// el.parentNode(inserted) <div id=​"app">​…​</div>​

insertedは親 Node に挿入された時に呼ばれるため、parentNode<div id=​"app">​…​</div>​)が存在する。

「update」ボタンをクリック時

this.message"Hello React!"になる。

updatecomponentUpdatedが呼ばれて以下がコンソール出力される。

// update
// el.innerHTML(update) Hello Vue!
// componentUpdated
// el.innerHTML(componentUpdated) Hello React!

updateが呼ばれた時点では、子コンポーネントの VNode({{ message }})は更新されていないため、el.innerHTMLの結果は"Hello Vue!"

componentUpdatedが呼ばれた時は、子コンポーネントの VNode も更新された後のため、el.innerHTMLの結果は"Hello React!"

「remove」ボタンをクリック時

this.message""になる。

今回紐付けをした要素はv-if="message"を付与しており、このタイミングで<h1 v-message v-if="message">{{ message }}</h1>が破棄されunbindが呼ばれる。

// unbind

「init」ボタンをクリック時(「remove」ボタンをクリックした後)

this.message"Hello Vue!"になる。

<h1 v-message v-if="message">{{ message }}</h1>が再生成され、bindinsertedが呼ばれて以下がコンソール出力される。

// bind
// el.parentNode(bind) null
// inserted
// el.parentNode(inserted) <div id=​"app">​…​</div>​

フック関数に渡される引数

el以外にも複数の引数が渡される。詳細は公式ドキュメントを参照。

ディレクティブフック引数

終わり

間違いがあれば、ご指摘いただけると幸いでございます。

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

Vue.jsのフレームワーク

はじめに

まずVue.jsに取り組もうと思った理由としては,友人とのプロジェクトの際にフロント開発をVue.jsを用いて開発していこうという話になったからである.名前は聞いたことはあるけど,使ったことはないし,jQueryとの違いも理解していないため,そこもとりあえず抑えていけるようにしていきたい.
また今回の課題の一つとしてはVue.jsのフレームワークである,"ElementUI"と"Vuerify"についても調べていき,今回の実装に関してどちらを用いるかまで検討していきたい次第である.

Vue.jsについて

まずjQueryはセレクタ操作に特化したものであるため,HTMLの一部を少し弄る分には十分すぎる機能を持っている(そこまでしっかり使ったことはないため,そんな感じなのか,みたいなイメージです笑).ただし,複数UIを連携させる場合などは,セレクタ操作であるため同期の面で困難が生じる.簡単な処理をする分には,低コストでの実装できるため,そこまでこだわる必要もないイメージを感じた.

次に肝心のVue.jsについてだが,仮想DOMを構成することにより,JSとHTMLを紐づけている様子.したがって,データ変更に対して勝手に表示するようになるため同期させる処理を書かなくてもよくなる.更新が多いページや状態管理が頻繁に起こるページなどに向いている.

実際のコーディングの違い

実際のコーディングがどうなるのか,簡単なもので考えていく.

jQuery

HTML
<div>
  Hello <span id="message">World</span> !
  <button id="update">change</button>
</div>
JavaScript
$(document).on('click', '#update', function() {
  $('#message').text('jQuery')
})

変更する部分をタグで囲むことによって,そこにJavaScriptを適用するようにしている.

Vue.js

HTML
<div id="app">
  Hello {{ message }} !
  <button @click="update">change</button>
</div>
JavaScript
new Vue({
  el: '#app',
  data: {
    message: 'World'
  },
  methods: {
    update() {
      this.message = 'Vue.js'
    }
  }
})

変化させたい部分を変数として持っておく.
@click="式・メソッド"とかくと,jQueryの$(element).on('click', ...)と同じ動きをする.

まとめ

Vue.jsについてはもう少し詳しく調べる必要がある.とりあえずはVue.jsの公式ページに記載.

フレームワーク

本題としてフレームワークである"Element"もしくは"Vuetify"のどちらかを用いたい.
したがって,まずはフレームワークについてまとめる

Element

フレームワークの一つであり,昔から使われているもの.コンポーネントを定義し,HTMLに記述することで利用することができる.コンポーネントにより,機能とUIを分離・再利用できるようになる.

導入

vue-clを使ってVue.jsをプロジェクトの準備をする.まずはグローバルにてvue-clをインストールする.

npm install -g vue-cli

webpackベースのプロジェクトを作成する.

vue init webpack my-project

最終的に,./my-project/ディレクトリが作成され、Vue.jsがインストールされる.
そのままプロジェクトに含まれるパッケージ群もインストールしておく.

cd my-project
npm install

次に,待望のElementをインストールする.

npm install element-ui -S

これで利用可能となるため,my-project/src/main.js以下でElementを読み込み日本のロケールをセット,ElementのCSSをを読み込む.

import Vue from 'vue'
import ElementUI from 'element-ui'
import locale from 'element-ui/lib/locale/lang/ja'
import 'element-ui/lib/theme-default/index.css'
import App from './App'

Vue.use(ElementUI, {locale})

new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

ここまでで準備が整ったため,my-project/src/App.vueでコンポーネントを利用することでElementを使うことができる.

まとめ

簡単な機能などは,特に苦労することなく実装することができそうである.

Vuetify

マテリアルデザインが浸透してきた現在でこそ,Vuetifyも最近使われてきている.VuetifyはVue.jsで使われるマテリアルデザインをベースとしたCSSのフレームワークである.ちなみに,同様のものとしてVue Materialもあるようだが,どうやらVuetifyの方がドキュメントの見やすさの点で優れている様子.

まとめ

どうやら,マテリアルデザインが主流となってきている現状,どうやらVuetifyの方がよく使われるそうである.
引き続きそれぞれの利点や実際に使って見た感想などを見ていきたいところである.

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

TruffleでDappを作る + VueとTypeScript

自分の備忘録としてDappの作り方の手順をまとめてみました。
最近やり始めたので間違いもあるかもしれません。ご承知ください。

環境構築

solidityのインストール

$ brew install solidity

truffleのインストールとプロジェクトの作成

$ npm install -g truffle
$ mkdir project && cd project
$ truffle init
$ vue create front

vue create時にtypescriptを選択します。

*****現状の環境*****

$ node -v
v11.9.0
$ npm -v
6.5.0
$ vue -V
3.3.0
$ solc --version
solc, the solidity compiler commandline interface
Version: 0.5.3+commit.10d17f24.Darwin.appleclang
$ truffle version
Truffle v5.0.3 (core: 5.0.3)
Solidity v0.5.0 (solc-js)
Node v11.9.0

* macOS Mojave version10.14

truffleプロジェクトの構造

上記に従ってプロジェクトの作成を行うと、以下のような構造を持つディレクトリが作られます。

-----contracts
 |---migrations
 |---test
 |---truffle-config.js
 |---front

ディレクトリの構造を理解するために、Dapp開発の流れを説明します。

Dapp開発の手順

  1. contractディレクトリにsolファイルを作成してコントラクトコードを書く。
  2. migrationディレクトリにデプロイのためのjsファイルを作成。
  3. testディレクトリにコントラクトコードをテストするファイルを作成。
  4. ganacheの導入
  5. terminalでtruffle migrateを行い、プライベートチェーン上にコントラクトをデプロイ
  6. フロント側でweb3.jsの設定を行う
  7. metamaskの導入
  8. 動作確認

contractディレクトリにsolファイルを作成してコントラクトコードを書く。

 solファイルはsolidityで書かれたファイルのことです。このファイルにコントラクトを書き込んでいきます。
 コントラクトはブロックチェーンのネットワーク上で利用できるアカウントであり、このコントラクト上で実行されるコードをコントラクトコードと呼びます。
 ここではブロックチェーンに関する解説は省きますが、ブロックチェーンのネットワークには送金などを行うアカウントコードとして実行されるアカウントが存在し、Dappでは後者を利用しています。

// Dogs.sol
pragma solidity ^0.5.0;

contract Dogs {
  // 犬のインスタンスを作っていきます
  struct Dog {
    uint id;
    string name;
  }

  // mappingはいわゆる連想配列のこと。ここではuint(id)をDogインスタンスに割り当てている。
  mapping(uint => Dogs) public dogs; // Dogインスタンスを格納
  uint public dogsCount; // インスタンス作成時のidとして利用(毎インスタンス生成時に+1していく)

  constructor() public { // 初期インスタンス生成
    createProgress("pochi");
  }

  function createProgress(string memory _name) private {
    dogsCount++;
    dogs[dogsCount] = Dog(dogsCount, _name);
  }
}

migrationディレクトリにデプロイのためのjsファイルを作成。

migrationディレクトリには、deployのためのファイルを作成します。

// migration/2_deploy_contract.js
let Dogs = artifacts.require("./Dogs.sol");
module.exports = function(deployer) { deployer.deploy(Dogs); };

上記のようにファイルを作成し、以下のコマンドを実行すると、contractsディレクトリに作成されたコントラクトをブロックチェーン上にデプロイします。

$ truffle migrate

また、今後開発を行なっていく上で、一度デプロイしたコントラクトコードを修正したいと思うことがあると思います。
その時は以下のコマンドを実行して新しいコントラクトコードでデプロイし直します。

$ truffle migrate --reset

railsをやったことがある人であれば、db:migrate:resetと同じような感じで考えていただければ良いと思います。

testディレクトリにコントラクトコードをテストするファイルを作成。

migrate --resetでやり直せるにしても、ブロックチェーンにデプロイされたものは修正が効かず、それゆえに改竄不可能性を持つわけですが、そうなるとバグや予想しない動作を含むものをデプロイするわけにはいきません。
こういった不具合を未然に防ぐためにもコントラクトコードのテストを行う方が良いです。
テストはsolidityでもjavascriptでも書くことができます。

// 飽くまで例です
// jsの場合
const Dogs = artifacts.require("./Dogs.sol");
contract("Dogs", function(accounts) {
  it("initializes with a dog", function() {
    return Dogs.deployed().then(function(instance) {
      return instance.dogsCount();
    }).then(function(count) {
      assert.equal(count, 1); // solファイルのconstructorで作成したデフォルトのインスタンス
    });
  });
});

ganacheの導入

ganache
ganacheはプライベートチェーン上に自動的に模擬アカウントを作成してくれるツールです。
以下のリンクからインストールできます。
https://truffleframework.com/ganache

ganacheを起動させてからコントラクトコードをプライベートチェーンにデプロイしてあげると、ganacheで生成されたアカウントがマイニングを行なってくれるので、すぐにコントラクトコードを実行できるようになります。

terminalでtruffle migrateを行い、プライベートチェーン上にコントラクトをデプロイ

ganacheを起動させた状態で、且つ、contractsディレクトリにsolidityファイル、migrationsディレクトリにdeploy用のjsファイル(testのファイルはここでの動作に影響はありませんが、soldityファイルにエラーがあればデプロイができなくなります)があることを確認してください。
その上で次のコマンドを実行してください。

$ truffle migrate

1_initial_migration.js
======================

   Replacing 'Migrations'
   ----------------------
   > transaction hash:    0xc3006c7464bb1e931d818226170e743976ca068ce15c92c0ad074f6a2685f71c
   > Blocks: 0            Seconds: 0
   > contract address:    0x8bBDf86104324ff2bA12d34F4D9D38eEe9e83748
   > account:             0x0f85Ddf6555a85e7bfb107faD34Fc13DF63475A4
   > balance:             99.92727632
   > gas used:            284908
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00569816 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00569816 ETH


2_deploy_contract.js
====================

   Replacing 'Dogs'
   ------------------
   > transaction hash:    0xb2e38fc03105dc5089418a24ede9f54559ca78264ce2ab9753f521e2338ee50f
   > Blocks: 0            Seconds: 0
   > contract address:    0x1EEB22378Ae20b4c18179E46F9C89D11B1f8Aa57
   > account:             0x0f85Ddf6555a85e7bfb107faD34Fc13DF63475A4
   > balance:             99.90698292
   > gas used:            972636
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.01945272 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.01945272 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0.02515088 ETH

デプロイができれば上記のようになります。

他の方法でデプロイができていることを確認するには、

$ truffle console

でtruffleのコンソールに入って、以下のようにコントラクトコードを実行してみることができます。

$ truffle console
truffle(ganache)> Dogs.deployed().then(function(dogs) { app = dogs })
undefined
truffle(ganache)> app.dogs(1).then(function(d) { dog = d })
undefined
truggle(ganache)> dog[1]
'pochi'

Dogs.deployed().then(function(dogs) { app = dogs })の部分で、appにdogsコントラクトを渡し、そのappを使って、app.dogs(1)のように、コントラクトコード上に定義したmappingにidを渡して該当のインスタンスを抜き出します。
最後にdog = dの部分で抜き出したインスタンスを変数に格納し、最後にそれの[1]番目の要素、つまりnameを参照しています。

このように名前を参照することができればデプロイできている証拠です。
次にフロント側の設定を行なっていきます。

フロント側でweb3.jsの設定を行う

それでは今度はフロント側を実装していきます。
ここではvue.jsとtypescriptを使っていきます。

まず、vue createでプロジェクトを作成してください。
作成時にtypescriptを利用する選択を行なってください。
cssもcssプリプロセッサを使うことで楽に記述できるようになるのでおすすめです。

$ vue create frontend

プロジェクトが作成されれば、中に入ってweb3とtruffle-contractのモジュールをインストールします。

$ npm install --save-dev web3@1.0.0-beta.37 truffle-contract

ここではweb3のバージョンを指定していますが、私の環境ではweb3だけでnpm installすると、このあと紹介するmetamaskというツールを利用した時にエラーが発生したので、これはその対処として行なっています。

vueとtypescriptの説明は行わないので、コンポーネントのファイルに書くブロックチェーンとやりとりするためのコードを解説します。
el-系のinputタグやbuttonタグはelementUIをインストールすると利用できるようになります。非常に使いやすいのでお勧めです。
https://element.eleme.io/#/en-US

*templateにはpugを利用しています。npm install --save-dev pug pug-plain-loaderで使えます。

<template lang="pug">
  #Contract
    .list(v-for="dog in dogs")
      p {{ dog.name }}
    .form
      el-input(v-model="name")
      el-button(@click="createDog") 作成
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Web3 from 'web3'
import TruffleContract from 'truffle-contract'
import artifacts from '../../../build/contracts/Dogs.json' // デプロイするとbuild/contracts配下に作成されます。
import $ from 'jquery'
const Dogs = TruffleContract(artifacts)

@Component({ components: { Dogs } })
export default class ProgressChainIndex extends Vue {
  private ownAddress: string = ""
  private name: string = ""
  private dogs: Array<object> = []

  created() {
    if (typeof web3 !== 'undefined') {
      web3 = new Web3(web3.currentProvider)
    } else {
      console.warn('No web3 detected.')
      web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:7545'))
    }

    Dogs.setProvider(web3.currentProvider)
    web3.eth.getCoinbase().then((account) => {
      this.ownerAddress = account
      Dogs.defaults({ from: account })
    });
  }

  beforeMount() {
    // ここでブロックチェーン上に記録されたデータを取得して画面上に表示する
    let dogsInstance
    let self = this
    Dogs.deployed().then(function(instance) {
      dogsInstance = instance
      return dogsInstance.dogsCount()
    }).then(function(dogsCount) {
      for (let i = 1; i <= progressId; i++) {
        // ブロックチェーン上のdogインスタンスを一つ一つ拾ってきて、そのidとnameをまとめたオブジェクトを作成、配列dogsに格納する
        dogsInstance.progresses(i).then(function(dog) {
          self.dogs.push({
            id: dog[0],
            name: dog[1]
          })
        })
      }
    }).catch(function(err) {
      console.warn(err)
    })
  }

  createDog() {
    // ブロックチェーンのコントラクトコードにインスタンスを記録
    let self = this
    Dogs.deployed().then(function(instance) {
      return instance.createProgress(
        self.name,
        { from: self.ownerAddress })
    }).catch(function(err) {
      console.error(err)
    })
  }
}
</script>

このコンポーネントを好きなように親コンポーネントに組み込んであげてください。

metamaskの導入

metamask
metamaskはブラウザとブロックチェーンを繋げるツールです。
このツールが実行されていれば、先ほどのコード上でweb3を認識することができます。
https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=ja

アプリケーションの実行

上記のようにコードを作成し、vueのディレクトリでnpm run serveを行います。
localhost:8080を開き、コンポーネントで配置したinputにdogの名前を入力して、作成ボタンを押します。
すると、ブロックチェーンへのアクセスを承認するか拒否するかの選択が表示されるので、承認ボタンを押しましょう。
承認後、作成したインスタンスをブラウザ上に反映させるためには一度リロードを行う必要があります。

また、ここでエラーが発生するようであれば、コードに何らかの原因があるか、ganacheやmetamaskの問題が考えられます。
ganacheの再起動やmetamaskでアカウントのリセットを行うと改善されることがあるので、その辺を確認してみましょう。

以下の動画は非常に参考になります。実際に動かしながら説明しているのでこのページを読むより楽かもしれません。
https://www.youtube.com/watch?v=3681ZYbDSSk

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