typeof Diary

VimとかJSとか。

NativeScript-Vueを触った

久々の更新。

2月にこんな発表がありました。
Announcing NativeScript-Vue 1.0

要約。「nativescript-vueの1.0が出たよ」

NativeScript

JavaScriptとかTypeScript、Angularを使って、ネイティブなモバイルアプリを作ることができるフレームワークです。
詳しいことは公式参照

JavaScriptでモバイルアプリと聞くと、React Nativeなんかもありますね。

で、今回はそれをVueで書けるでっていうやつです。
最近Vue推しの自分にとっては格好のおもちゃですね。

早速遊びます。

準備

まずはNativeScriptがないと始まりません。

npm install -g native-script

次にモバイルアプリなので、こっちもやっておいてください。
IOSだけなら、JDKは入れなくてもまぁOK。
NativeScript Advanced Setup: macOS

長いのでカット。

次に、vue-cli放り込みましょう。プロジェクトのテンプレート作ってくれます。

npm install -g @vue/cli @vue/cli-init
vue init nativescript-vue/vue-cli-template <project-name>
cd <project-name>
npm install

npm installまで終わったら、npm run watch:<platform>を実行します。
今回はIOSなので、npm run watch:iosとします。

すると、シミュレーターが開くはず。
f:id:lisia:20180310220241p:plain

ひとまずここまで。
基本はここの通りです。

アプリを動かす

シミュレーター動いたのは良いけど、アプリないやん!って話ですよね。
多分そもそもビルドされてないから・・・?

package.jsonのscript内を見てみると、使えるコマンドが分かります。
package.json抜粋

  "scripts": {
    "build": "webpack --env.tnsAction build",
    "build:android": "npm run build -- --env.android",
    "build:ios": "npm run build -- --env.ios",
    "debug": "webpack --watch --env.tnsAction debug",
    "debug:android": "npm run debug -- --env.android",
    "debug:ios": "npm run debug -- --env.ios",
    "watch": "webpack --watch --env.tnsAction run",
    "watch:android": "npm run watch -- --env.android",
    "watch:ios": "npm run watch -- --env.ios",
    "clean": "rimraf dist"
  },

それっぽいnpm run debug:ios叩いてみます。

f:id:lisia:20180310220514p:plain

こんな感じでサンプルアプリが立ち上がりました。
(この後、watchしたら大丈夫でした。)

ちょっとサンプルを作ってみる

APIも叩きたいので、GiphyのAPI叩いてgifを表示するようなものにしてみます。
Vuexのサンプルで作ったことがあるこれが元ネタ。

サンプルなので、ひとつのコンポーネントにまとめてしまいます。

とりあえず画面を作る

src以下がコードを書くところです。
src/components以下にGiphy.vueを作成します。
touch src/components/Giphy.vue

<template>
 <Page class="page">
    <ActionBar class="action-bar" title="Giphy">
      <NavigationButton
        text="Go Back"
        android.systemIcon="ic_menu_back"
        @tap="$router.push('/home')"
      />
    </ActionBar>

    <StackLayout>
      <label text="Welcome to GiphyPage!"/>
    </StackLayout>
  </Page>
</template>

HelloWorldを真似て、こんな感じでtemplateを書いておきます。
次に、ページへのルーティングが必要なのでsrc/router/index.jsに書き加えます。

// ...
import Giphy from '../components/Giphy'

const router = new VueRouter({
  pageRouting: true,
  routes: [
    // ...
    {
      path: '/giphy',
      component: Giphy,
      meta: {
        title: 'Giphy'
      }
    }
  ]
}) 
// ...

homeの画面もボタンを追加しておかないとですね。

<StackLayout>
  <Button class="btn btn-primary" @tap="$router.push('/counter')">Counter</Button>
  <Button class="btn btn-primary" @tap="$router.push('/hello')">Hello World</Button>
  <Button class="btn btn-primary" @tap="$router.push('/giphy')">Giphy</Button>
</StackLayout>

画面を確認してみましょう。
f:id:lisia:20180310220536p:plain

タップして、画面が遷移することを確認します。
f:id:lisia:20180310220549p:plain

文字見えにくいけど気にしない。とりあえず、画面遷移を文字が表示できました。

処理とか入れていく

テンプレートに関しては、検索用のテキストボックスと表示領域があれば事足ります。
処理の流れは、テキストが入力されたらGhipyのAPIを叩いて、その結果をテンプレートに表示する。

これだけです。
では早速、まずはテンプレート。

<template>
  <Page class="page">
    <ActionBar class="action-bar" title="Giphy">
      <NavigationButton text="Go Back" android.systemIcon="ic_menu_back" @tap="$router.push('/home')"/>
    </ActionBar>

    <ScrollView>
      <StackLayout>
        <SearchBar
          :text="searchWord"
          hint="Please input search word"
          color="#000"
          margin="20"
          v-model="searchWord"
          @textChange="handleChangeSearchWord"
        />
        <template v-if="gifList.length">
          <Image
            v-for="(gif, index) in gifList"
            :src="gif.images.fixed_height_still.url" stretch="none"
          />
        </template>
      </StackLayout>
    </ScrollView>
  </Page>
</template>

続いて、script部分。

export default {
  name: 'Giphy',

  data() {
    return {
      searchWord: '',
      gifList: []
    }
  },

  methods: {
    handleChangeSearchWord() {
      const params = encodeURIComponent(this.searchWord).replace(/%20/g, '+')
      const url = `https://api.giphy.com/v1/gifs/search?api_key=YOURAPIKEY&q=${params}`

      fetch(url)
      .then(res => res.json())
      .then(json => {
        this.gifList = json.data
      })
    }
  }
}

軽く説明。

テンプレート側は、スクロールさせたいので、<ScrollView>で囲んでいます。
検索は<TextFiled>を最初は使っていたのですが、ドキュメント読んでると、<SearchBar>なるものがあったので、こちらを採用。

script側も特に言うことはなくて、単純にAPIを叩いているだけです。
結果をdataのgifListに放り込みます。

完成!

f:id:lisia:20180310220403g:plain

まとめ

  • JavaScriptでモバイルアプリ書ける 便利
  • しかもVue使える 便利
  • 慣れ親しんだもので書けるのはやっぱり 便利

以上!