20210308のvue.jsに関する記事は11件です。

配列・オブジュエクトの変更をリアクティブに検出するには

数字や文字列などは簡単に検出できるが、配列・オブジェクトは一工夫必要

TL;DR

Vue.set() を利用して変更させる

やってみる

直接変更させた場合

<template>
  <div class="center">
    <div class="row">
      <div v-if="bool">ON</div>
      <div v-else>OFF</div>
      <button @click="bool = !bool">真偽値</button>
    </div>
    <div class="row">
      <div v-if="array[0]">ON</div>
      <div v-else>OFF</div>
      <button @click="array[0] = !array[0]">配列</button>
    </div>
  </div>
</template>

<script>
export default {
  layout: 'plain',
  data() {
    return {
      array: [false],
      bool: false
    }
  }
}
</script>

<style>
.center {
  width: 100px;
  margin: 0 auto;
}

.row {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}
</style>

sample1.gif

単体のboolは値の変更に合わせて表示も切り替わるが、配列はそうもいかない(配列の値自体は変わっている)

配列の値をVue.set()で変更させる

中身を直接変更するのではなく、 Vue.set(Array, index, value) を利用してみる。
ここの例では、エイリアスである this.$set() にしています。

詳しいドキュメントはこちら

<template>
  <div class="center">
    <div class="row">
      <div v-if="bool">ON</div>
      <div v-else>OFF</div>
      <button @click="bool = !bool">真偽値</button>
    </div>
    <div class="row">
      <div v-if="array[0]">ON</div>
      <div v-else>OFF</div>
      <!-- 配列の値の変更の仕方を変える -->
      <button @click="changeValue()">配列</button>
    </div>
  </div>
</template>

<script>
export default {
  layout: 'plain',
  data() {
    return {
      array: [false],
      bool: false
    }
  },
  methods: {
    changeValue() {
      this.$set(this.array, 0, !this.array[0])
    }
  }
}
</script>

<style>
/* 省略 */
</style>

sample2.gif

いいかんじ!

まとめ

Vueでは配列の中身や長さ、オブジェクトのプロパティの追加や削除の検出ができないため、それを可能にするためにVue側でメソッドが用意されていたんですね。

意外とこれに気づかずに実装を進めて、後々になって「何でここだけ動いてないん...?」となったのは自分の他にもいるんじゃないでしょうか...

備考

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

[Electron, Vue.js] IpcRenderer.on()でthis.countに代入しようとしたら失敗した

動機

ElectronのipcRenderer.on()内でthis.countに受け取った値を代入したかったのにうまく行かなかったので
解決はしたが原因がわかりません…

目次

うまくいかない例

  mounted() {
    ipcRenderer.on("setCount", (_, arg) => {
      this.count = arg;
    });
  },

うまくいく例

なかなかグロテスクなコードになりました…
thisをコールバックの外に出してみたら何故かうまく行った

  async mounted() {
    this.count = await ((): Promise<string> =>
      new Promise((resolve) => {
        ipcRenderer.on("setCount", (_, arg) => {
          resolve(arg);
        });
      }))();
  },

関数を分けるなら

  methods: {
    async waitIpcMessage(): Promise<string> {
      return new Promise((resolve) => {
        ipcRenderer.on("setCount", (_, arg) => {
          resolve(arg);
        });
      });
    }
  },
  async mounted() {
    this.count = await this.waitIpcMessage();
  }

最後に

なぜこれならうまくいくのか知っている方は教えてください...
thisが外に出てるからうまくいくっぽい?よくわかりません

話は逸れますが非同期周りの書き方ってかなり複雑ですよね

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

Vue.js始めました。

*学習初日の個人的なアウトプット用です。

Vue.jsとは、UIを構築するためのプログレッシブフレームワークであり、モダンなツールやサポートライブラリと組み合わせることで、洗練されたSPAを開発することもできる。

大きな特徴の一つとして、双方向データバインディングができるという点が挙げられる。
データバインディングとは data と UI を結び付けるという意味で、双方向というのは data を更新すれば UI が更新されて、 UI を更新すれば data が更新されるという意味である。

入門のためここでは名前と簡単なリストを表示させる。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Vue practice</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div id="app">
  <!--二重波括弧 {{}} で表現し UI を反映させる。そのままJavaScriptの式を書くこともできる。 -->
    <p>Hello {{ name.toUpperCase() }}!</p>

  <!-- v-model を使うことで input タグに入力された文字を上の表示にリアルタイムで反映できる。-->
    <p><input type="text" v-model="name"></p>

    <h1>My Lists</h1>
    <ul>
      <li>{{ lists[0] }}</li>
      <li>{{ lists[1] }}</li>
      <li>{{ lists[2] }}</li>

      <!-- 上のリストは v-for を使って配列の中身を取り出すことが可能 -->
      <li v-for="list in lists">{{ list }}</li>
    </ul>
  </div>

 <!-- Vue.jsを読み込む -->
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>

  <script src="js/main.js"></script>
</body>
</html>
  • v-for や v-model など v- から始まる特殊な属性をディレクティブと呼ぶ。
js/main.js
(function() {
  'use strict';

  // vm は view model の略
  var vm = new Vue({
    el: '#app', // el は elements の略
    data: {
      name: 'tanaka',
      lists: [
        'list 1',
        'list 2',
        'list 3'
      ]
    }
  });
})();

ブラウザで確認すると結果以下のような表示になる。

Image from Gyazo

以上です。

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

Vue.js始めてみました①

この度Vue.jsを学び始めました。
その勉強内容をまとめます。

Vue.jsとは

Evan Youさんという方が手軽に小規模なアプリケーションを作れることを目的に作られたフレームワーク。
SPA(シングルページアプリケーション)なので1つのページの変化があった部分だけ表示を変える。
その為、読み込みが少なくスムーズで切り替えが素早い。

個人的にはEvanさんは日本のアニメが好きなのでVue.jsの各バージョンのコードネームが日本のアニメからきていることに親近感を覚えました。
Dragon BallとかHunter×Hunterとか。可愛いな。

インストール

Vue.jsインストールページ

上記に記載されている通り

  • CDN
  • ダウンロード
  • Vue-cli

の3つの方法があります。

一番手軽なのがCDNだと思います。
1行コードをheadに組み込むだけで使えるようになります。(開発バージョンと本番バージョンがあリます)
本日時点では以下ですが、公式サイトから必ず確認してください。

開発バージョン
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>

開発バージョンと本番バージョンの違いは、開発バージョンだと警告文を出力してくれるなどあるみたいです。

使ってみる

以下のようにheadにCDNを組み込みます。

<head>
  <meta charset="UTF-8">
  <title>Sample</title>
  <link rel="stylesheet" href="style.css" >

// 以下を追加
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>

</head>

以下のようにHTML要素を作ります。(説明だけなのでテキトーです)

<div id="app">
  <p>{{ text }}</p>
</div>

以下のようにVueインスタンスを作成します。
script要素で作成します。

<script>
  new Vue({
    el: '#app',
    data: {
      text:'Hello!World'
    }
  })
</script>

上記のように記述するとdataの内容がHTML要素のtextに反映され、Hello!Worldとブラウザ上に表示されます。

Vueインスタンスの中身

new Vue({
  el:どのHTML要素とつなげるか
  data:どのデータを入れるか
  methods:処理内容
  computed:どのデータを使って計算するか
  watch:データの監視
})

上記のように作成します。

一旦ここまでです。

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

axiosでREST APIの通信を行う時にSafariではエラーが起きたときの対処法

皆さんこんにちは!

Windowsで開発している僕にとってはSafari特有のエラー程苦しむものは無いです。

ただ、この時代スマートフォンの使用率が圧倒的に高い10代、20代のほとんどはiPhoneを使っていると思います。

僕の周りでもiPhoneの使用率が圧倒的に高いです。

なので、iPhoneのエラーも無視するわけにはいかない。。。

今日はそんなこんなでaxiosでLaravelで作成したバックエンドとの通信でWindows環境で開発しているので、エラー内容は確認できなかったのですが、おそらくCORSエラーが原因でAPI通信を行うことができませんでした。

結論から言いますと、SafariではChromeのように上手くキャッシュの処理を行うことができないそうです。

なので、このキャッシュの問題を解決してあげることでSafariでもAPI通信を行うことができます!

それでは、説明を見ていきましょう!

はじめに

今回は、Vueでの説明となります。

もし、Reactなどを使っている場合は適時変更して下さい。

また、バックエンドではLaravelでCORSドメインの設定などを行います。

もし、Laravel以外でAPIを作成している場合も適時変更してください。

axiosでCookie設定

axiosのデフォルトでは、withCredentialsというCookieを使えるようにするためのプロパティの設定がOFFになっています。

なので、これをONにしてあげましょう!

main.js
// axiosのプロトタイプ宣言
Vue.prototype.$axios = axios
// Cookieの使用を可とする
axios.defaults.withCredentials = true

これでaxiosがデフォルトでCookieを使用することができます。

CORSドメイン設定

次に、axiosでCookieの情報を受け取るためにバックエンドで適切なヘッダーを追加してあげましょう!

> php artisan make::middleware ApiCors
Http/Middleware/ApiCors.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class ApiCors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // すべてのレスポンスに CORS 用のヘッダーを追加する必要はないので URL から判断する
        $paths = explode('/', $request->getPathInfo());
        if ($paths[1] === 'api') {
            return $next($request)
            ->header('Access-Control-Allow-Origin', config('cors.allowed_origins'))
            ->header('Cache-Control', 'no-cache max-age=3600')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Credentials', 'true')
            ->header('Access-Control-Allow-Headers', 'X-XSRF-TOKEN, Authorization, content-type, Transfer-Encoding, Accept, Accept-Encoding, Accept-Language');
        }
        return $next($request);
    }
}

$paths = explode('/', $request->getPathInfo());if ($paths[1] === 'api')/api/apis``のようなAPI通信を行う時だけこのミドルウェアを適用するようにしています。

Access-Control-Allow-Origin

Access-Control-Allow-OriginではCORSドメインを許可するドメインを登録しています。

例えば、http://localhost:3000からのリクエストを許可したい場合はここにhttp://localhost:3000と入力してください。

これを*のようにすると全てのドメインからリクエストが可能なので、データ抜き放題となるので注意して下さい。

Access-Control-Allow-Methods

Access-Control-Allow-Methodsでは、使用できるメソッドを書きます。ほとんどの場合は上記のようにしてOKです。

Access-Control-Allow-Credentials

Access-Control-Allow-Credentialstrueにすることで、先ほどaxiosで設定したCookie情報のリクエストを受け取れるようにしています。

Access-Control-Allow-Headers

最後に、Access-Control-Allow-Headersを説明します。

これが重要です!

色々あるのですが2つだけ説明します。

X-XSRF-TOKENはaxiosで発行したトークン情報です。PHPで言うと、formCSRFのようなものです。これを受け取るためにこのヘッダーを追加します。

次に、content-typeです。

これは、GETやHEADの場合は必要ないのですが、以下のようなリクエストを行う場合content-typeapplicatio/jsonとなります。

this.$axios
        .post(process.env.VUE_APP_LARAVEL_SITE_URL + '/api/participants', {
          name: 'akki'
        })

そして、content-typeのデフォルトではapplication/jsonは対応していません。

なので、このようなapplication/jsonの形を受け取るのを許可するためにcontent-typeを追加します。

ちなみに場合によっては、content-typeでエラーが出ます。その時はContent-Typeと設定して見て下さい。

ミドルウェアの適用

最後に作成したこのミドルウェアを適用させましょう!

App/Http/Middleware/Karnel.phpを開いてください。

Karnel.php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        // CORSドメインの設定を追加
        \App\Http\Middleware\ApiCors::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];
    // 省略
}

必ず$middlewareに追加してください!!

なぜかと言うと、$middlewareに追加しないとOPTIONSリクエストに今作成したミドルウェアを適用することができません!

絶対に$middlewareに追加!!!

いかがだったでしょうか?

このエラーで3日程時間を費やされたので、本当に苦労しました。

ぜひ皆さんのお力になれたらなと思います。

以上、「axiosでREST APIの通信を行う時にSafariではエラーが起きたときの対処法」でした!

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。

気になる方はぜひ一度ご相談ください!

Thank you for reading

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

フロントエンドVue.js バックエンドFlaskの開発で躓いたこと色々

GoogleのOAuthをする場合

元々はFlaskのみで実装していたプロジェクトだったのだが、途中からフロントエンドをvue.jsに引き継いだため、OAuth部分をFlask側のコードで実行しようとしていた。
これだとCORSエラーが出てしまう。
CORSエラーへの対応について調べてみると、Flask,Vue.jsともにCORS対応方法についての文献がでてくる。
しかしこれをやっても超えられない。何故か。

色々と探してみたのだが、そもそもそういう使い方は出来ないっぽい。探しすぎてソースを見失ってしまったが、つまりそういうことだったんだと思う。
素直にVue.js側でvue-google-oauth2を使った実装を行う事によってVue.js→Google→Vue.jsという通信によってtokenが取得できるのでそれを使う。

認証されないGoogleAPIキー

これはそのままこれ
https://qiita.com/kenken1981/items/9d738687c5cfb453be19

どうも、Google認証の「OAuth 2.0 クライアント ID」は、一度あるポートで使うと、その後で違うポートで利用することはできないらしい。

ということで、別途フロントエンド用のキーを作って、vue.js側のポートを指定することで解決。

認証されないGoogleAPIキー2

承認済みの JavaScript 生成元
については、127.0.0.1 は使えない。
https://qiita.com/kenken1981/items/b6cb3e536668a3cef520

Google認証は、「127.0.0.1」というIPアドレスは認めておらず、「actual urls」というらしい?いわゆるaaa.jpやbbb.comといった形式でないとエラーを返す模様。

Vue.js側で環境変数が読み込まれない

Vue.js側は yarn build することでdistフォルダに静的ファイルを吐き出す形で利用しているのだが、どうもVue.js側で環境変数を読み込んでくれない。
.envに書いてあろうが読み込まれない。何故か。

buildする時に、その設定が必要だった。
詳細についてはここにある通り。
https://qiita.com/go6887/items/2e254d31b5a4af42f813

vue.js が
/frontend
内に入っていて、/frontoend でビルドコマンドを打つ形にしてありましたが
/frontend/.env.development
というファイルを作って、中に変数を記述。

package.json には
"build": "cross-env NODE_ENV=development vue-cli-service build --mode development --dest ../dist",

みたいな形に書いておく事によって環境変数が読み込まれた。

変更履歴

2021/3/8 初稿up

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

Vue.jsコンポーネントの記述順序(options order)の表

本家スタイルガイド - コンポーネント/インスタンス オプション順序の転記。スクロールしないで読めるように。

分類 オプション
1. 副作用 el
2. グローバルな認識 name, parent
3. コンポーネントの種類 functional
4. テンプレートの修飾子 delimiters, comments
5. テンプレートの依存関係 components, directives, filters
6. 合成 extends, mixins
7. インタフェース inheritAttrs, model, props/propsData
8. ローカルの状態 data, computed
9. イベント watch
beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, destroyed
10. リアクティブではないプロパティ methods
11. レンダリング template/render, renderError

※何となくよく探しそうなやつは太字で

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

Vue.jsで作図する 凸レンズの焦点問題

突然ですが、こんな図みたことありますよね?
スクリーンショット 2021-03-07 002551.png
これは理科で定番の凸レンズの焦点に関する問題です。
今回はこの焦点問題を理解しつつVue.jsで作図することを目指します。

作ったもの ※PC推奨:
https://convex-lens-d0f3c.web.app/

github ソースコード:
https://github.com/tenugui-taro/convex-lens_public

準備

Vue2 × composition-api × Vuetify の構成で作ります。

$ vue create {project-name}
$ npm install @vue/composition-api
$ vue add vuetify

composition-apiを有効にするにはmain.tsで設定が必要になります。
@vue/composition-api

src/main.ts
import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)

焦点問題とは

ざっくりいうと凸レンズに入射した光が集まる位置に実像ができる。
虫眼鏡でものが大きくみえる現象はこの原理を利用していたりする。

焦点は凸レンズに平行に入射した光が集まる場所
ちなみに、凸レンズの中心から焦点までの距離の2倍に光源があると光源と実像は同じ大きさになる。

解答のポイントは光の線を引きその交点を求めること。

  • 光軸と平行な線
  • 凸レンズの中心を通る線
  • 焦点を通る線

スクリーンショット 2021-03-08 043257.png

線を引く

解答のポイントとなる、光源から出る線を引く方法を考えます。

vuetifyで作図

Vuetifyのドキュメントを眺めているとグラフ作成用UIコンポーネントがありました。
v-sparkline

なんとなくおしゃれだしこれで。
まずはサンプルをcomposition-apiを使いつつコンポーネント化します。

src/components/Sparkline.vue
<template>
  <v-sparkline
    :value="value"
    :gradient="gradient"
    :smooth="radius || false"
    :padding="padding"
    :line-width="width"
    :stroke-linecap="lineCap"
    :gradient-direction="gradientDirection"
    :fill="fill"
    :type="type"
    :auto-line-width="autoLineWidth"
    auto-draw
  />
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs } from "@vue/composition-api";

const GRADIENTS: string[][] = [
  ["#222"],
  ["#42b3f4"],
  ["red", "orange", "yellow"],
  ["purple", "violet"],
  ["#00c6ff", "#F0F", "#FF0"],
  ["#f72047", "#ffd200", "#1feaea"],
];

export default defineComponent({
  setup() {
    const state = reactive({
      width: 2, // 線の太さ
      radius: 10, // 線同士のつながり 小さいほど角張る
      padding: 8, // 描画エリアの余白
      lineCap: "round", // 線端の形状
      gradient: GRADIENTS[5], // 配色 
      value: [0, 2, 5, 9, 5, 10, 3, 5, 0, 0, 1, 8, 2, 9, 0], // 値
      gradientDirection: "top", // グラデーションの方向
      fill: false, // グラフの塗りつぶし
      type: "trend", // グラフの種類 trend or line
      autoLineWidth: false, // 自動で線を拡張してくれる?
    });

    return {
      ...toRefs(state),
    };
  },
});
</script>

おしゃれなグラフが表示されました。
sparkline4.gif

焦点問題の作図をイメージして、3本の線を引きます。
線を重ねるためにpositionを設定しています。

src/App.vue
<div style="position: relative">
  <Sparkline style="position: absolute" :value="[100, 100, 0]" />
  <Sparkline style="position: absolute" :value="[100, 0, -100]" />
  <Sparkline style="position: absolute" :value="[100, -100, -100]" />
</div>

sparkline5.gif

いい感じ......
あれ、他要素との座標をどうやって合わせる......?

ただ単純に用意した画像を重ねると以下の通り、これでは0点です。
スクリーンショット 2021-03-07 162240.png
ここからどうするか......
ごまかしでwidthやheightを調整するうちに心が痛くなったので別の手段を考えます:innocent:

svgで表現する

図形を組み合わせながら問題を用意します。

src/App.vue
<svg
  xmlns="http://www.w3.org/2000/svg"
  width="90vw"
  height="70vh"
  id="drawing-area"
>
  <ellipse cx="50%" cy="50%" rx="3%" ry="40%" fill="white" stroke="black" />
  <line
    x1="10%"
    y1="50%"
    x2="90%"
    y2="50%"
    stroke-width="1%"
    stroke="#455A64"
  />
  <circle cx="35%" cy="50%" r="1%" fill="#E0E0E0" stroke="black" />
  <circle cx="65%" cy="50%" r="1%" fill="#E0E0E0" stroke="black" />
  <rect x="20%" y="30%" width="1%" height="20%" fill="#e74c3c" />
</svg>

スクリーンショット 2021-03-08 010407.png
いよいよ作図します。
線を描画する関数、実像を描画する関数を用意しひとまず手計算した値を渡します。

src/utils/addLine.ts
/**
 * 線を描画
 * @param {number[]} params
 */
export const addLine = (params: number[]) => {
    const drawingArea = document.getElementById("drawing-area");
    const line = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "line"
    );

    line.setAttribute("x1", `${params[0]}%`);
    line.setAttribute("y1", `${params[1]}%`);
    line.setAttribute("x2", `${params[2]}%`);
    line.setAttribute("y2", `${params[3]}%`);
    line.setAttribute("stroke", "black");
    drawingArea!.appendChild(line);
}
src/utils/addRect.ts
/**
 * 四角形を描画
 * @param {number[]} params
 */
export const addRect = (params: number[]) => {
    const drawingArea = document.getElementById("drawing-area");
    const rect = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "rect"
    );

    rect.setAttribute("x", `${params[0]}%`);
    rect.setAttribute("y", `${params[1]}%`);
    rect.setAttribute("width", `${params[2]}%`);
    rect.setAttribute("height", `${params[3]}%`);
    rect.setAttribute("fill", `#e74c3c`);
    drawingArea!.appendChild(rect);
}
src/App.vue
onMounted(() => {
  // addLine([x1, y1, x2, y2])
  // 凸レンズの中心を通る線
  addLine([20, 30, 80, 70]);

  // 光軸に対して平行な線
  addLine([20, 30, 50, 30]);
  addLine([50, 30, 80, 70]);

  // 焦点を通る線
  addLine([20, 30, 50, 70]);
  addLine([50, 70, 80, 70]);

  // addRect([x, y, width, height])
  // 実像
  addRect([80, 50, 1, 20]);
});

スクリーンショット 2021-03-08 010125.png
作図できました!100点:cherry_blossom::cherry_blossom:

自動化

もちろん手計算は面倒です。
交点を算出する関数を用意し、vueファイルとは別に切り出します。
計算ばかりなので興味ある方はソースコードを参照ください。

また、好きに動かせるようv-sliderコンポーネントを入れて完成です。
200点:cherry_blossom::cherry_blossom::cherry_blossom:
sparkline5.gif

ところで焦点の内側に入ると実像が出来ていませんね。
このときは、虚像が出来るのですが今回は実装見送りです......

ホスティング

最後にfirebaseにホスティングして終了です。
https://firebase.google.com/docs/hosting?authuser=0

$ firebase init hosting
$ firebase deploy --only hosting

作ったもの ※PC推奨:
https://convex-lens-d0f3c.web.app/

まとめ

凸レンズをふと思い出して作ってみました。
失敗もしましたがv-sparklineの使い方を学べたのでよしということで。

また、前回記事よりはまとまった記事にできた気がします。
今後もしょうもないことに取り組んでVueと仲良くなっていきたいです。

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

imgのファイル指定をv-bindでする時

Vue.jsでimgタグのsrc指定を変数で行う場合、そのままだと使えないので注意

TL;DR

require()を使用する

やってみる

※この例ではNuxtも使用しています

そのまま変数を置いてみる

<template>
  <img :src="pass">
</template>

<script>
export default {
  data() {
    return {
      pass: '~/assets/test-img.png'
    }
  }
}
</script>

なんとなくいけるような気はするが、結果は 404エラー となってしまいます。
どうやら、相対パスを表す ~ 部分が、 そのまま文字列として 読み込まれてしまっている模様。(たぶん)

モジュールとして読ませる

そこで、 require() を利用する。

<template>
  <img :src="pass">
</template>

<script>
export default {
  data() {
    return {
      pass: require('~/assets/test-img.png')
    }
  }
}
</script>

これで晴れて表示させることができます!(表示例がないのでわかりにくいですが...)

(おまけ)static配下の画像の場合

指定したい画像がstatic配下だと、require使わずとも表示させることができます。

<template>
  <img :src="pass">
</template>

<script>
export default {
  data() {
    return {
      pass: 'test-img.png'
    }
  }
}
</script>

template内で直接指定する場合、
~/static/test-img.pngtest-img.png と書くことで、自動でstatic配下に補完してくれるようです。
相対パスの記述がないので、変数で文字列として読ませても、うまく作動するようです。

便利〜〜〜

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

Form SubmitでAPIコールすると失敗

フロントエンド(HTML/CSS/JavaScript)強化中で、いろいろ試している所です。

HTMLでFormを作成して、画面操作を契機としてJavaScript(Vue.js)の処理を連動させてAPIコールする、というコードを書きましたが、つまづきました。

いろいろと試してみた結果、
・<input type="submit" だと失敗
・<input type="button" だと成功
という結果となりました。

開発内容

Vue.jsを利用して、画面操作を契機にAPIコールすることを試すだけが目的ですので、開発内容は非常に単純です。
要件:
・郵便番号をテキストボックスから入力し、ボタンクリックしたことを契機にAPIをコール。
・利用したAPI: https://zipaddress.net/
・APIのレスポンスから、都道府県名を取得してアラート表示。
・APIコールでExceptionが発生した場合: アラート「Fail to call API」
・APIのレスポンスに、異常値が設定されていた場合: アラート「Error was returned」

最初に書いたコード

practice_submit.html
<!DOCTYPE html><html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
</head>
<body>
    <div id="apiTest">
        <h2>Form Click</h2>
        <form method="post">
        <tr>
            <td>郵便番号</td>
            <td><input type="text" v-model="zipcode"/></td>
        </tr>
            <input type="submit" @click="getAddress" value="送信"/>
        </form>
    </div>
    <script type="text/javascript" src="./practicevue.js"></script>
</body>
</html>
practice.js
new Vue({
    el: "#apiTest",
    data: {
        zipcode: ""
    },
    methods: {
      getAddress: function() { 
        var url = new URL('https://api.zipaddress.net/');
        var param = {zipcode: this.zipcode};
        url.search = new URLSearchParams(param);

        fetch(url)
        .then(response => {
          return response.json();
        })
        .then(function(jsonData){
            if(jsonData.code == '200') {
              alert(jsonData.data.pref);
            } else {
              alert('Error was returned');
            }
        }).catch(err => {
          alert('Fail to call API');
        });
      }
    }
})

画面

以下のように、郵便番号を入力するためのテキストボックスと送信ボタンがあるだけの単純な画面です。
スクリーンショット 2021-01-21 0.22.44.jpg

発生した問題

上記のvuepractice.js で、fetch(url)を行った結果、Exceptionが発生してしまったようです。
以下のアラートメッセージが表示されたので、APIコールしたサーバからエラーが返されたのではなく、
「 }).catch(err => { 」
に該当して、HTTPリクエスト送信処理自体で例外が発生した、と考えられます。

スクリーンショット 2021-01-21 0.13.40 copy.jpg

        }).catch(err => {
          alert('Fail to call API');
        });

解決方法

いろいろ試してみましたが、HTMLのinput属性を、submitからbuttonに変更するだけで、解決しました。
変更前: <input type="submit" @click="getAddress" value="送信"/>
変更後: <input type="button" @click="getAddress" value="送信"/>

郵便番号に「1000000」を設定して送信ボタンをクリックした結果、想定通りに都道府県名を正常に取得できました。

スクリーンショット 2021-01-24 18.15.20.jpg

修正後のHTML

上記の通り、1行変更しただけですが、修正後のHTMLは以下です。

practice_submit.html(修正後)
<!DOCTYPE html><html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
</head>
<body>
    <div id="apiTest">
        <h2>Form Click</h2>
        <form method="post">
        <tr>
            <td>郵便番号</td>
            <td><input type="text" v-model="zipcode"/></td>
        </tr>
            <input type="button" @click="getAddress" value="送信"/>
        </form>
    </div>
    <script type="text/javascript" src="./practicevue.js"></script>
</body>
</html>

考察

buttonと、submitの違いだけでなぜこうなる...?
いまいちわかりませんでしたが、これで良しとしました。

しかし、ここで気付きました。
「submit」しないのでれば、formである必要がないじゃないか!!

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

ElectronのexecuteJavascriptでError: Script failed to executeが出る件

はじめに

初投稿です...
ElectronのBrowserViewでexecuteJavascriptを使った際、一見正しそうなスクリプトがエラーを吐く問題で少々悩んだので備忘録として。

問題のソースコード

要素の取得に失敗したらfalse、成功したら真を返したい

      const result = await browserView.webContents.executeJavaScript(`
        const anko = document.getElementById("anko"); 
        return anko == null ? false : true;
      `)

正しいソースコード

どうやらreturnで返しちゃだめらしいです。(そんなん知らんよ…)
最後に評価された値が返却されるらしい。

      const result = await browserView.webContents.executeJavaScript(`
     let val = true;
        const anko = document.getElementById("anko"); 
        anko == null ? false : true;
      `)

現在作っているアプリ

Youtube Live用のコメントビュワーです(Electron製)(ベータ版)
配信する方はぜひどうぞ
- https://tubug.netlify.app

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