- 投稿日:2020-11-16T23:18:02+09:00
Vue CLIで新規プロジェクトを作成する
環境は以下で作成
- node
- 14.15.0
- vue cli
- 4.5.8
事前準備
docker-compose.yaml
とDockerfile
を準備docker-compose.yamlversion: '3' services: sample-front: build: <path-to-dockerfile> container_name: sample-front tty: true volumes: - ./../sample-front/:/app ports: - "8080:8080"Dockerfile
FROM node:14.15.0-alpine3.12 ENV VUE_CLI_VERSION 4.5.8 RUN yarn global add @vue/cli@${VUE_CLI_VERSION} WORKDIR /appコンテナ立ち上げ
⛄ docker-compose up確認
⛄ docker psコンテナに入る
⛄ docker exec -it sample-front ashインストールしたもののversion確認(スキップ可)
/app # node -v v14.15.0 /app # vue --version @vue/cli 4.5.8プロジェクト作成
今回はカレントディレクトリに作成
vue create .カレントに作らない場合は、以下のコマンドを使用
vue create <app-name>設定は好みがあると思うのでお好きなように
Vue CLI v4.5.8 ? Generate project in current directory? (Y/n) -> Y ? Please pick a preset: (Use arrow keys) Default ([Vue 2] babel, eslint) ❯ Default (Vue 3 Preview) ([Vue 3] babel, eslint) Manually select features ? Pick the package manager to use when installing dependencies: (Use arrow keys) ❯ Use Yarn Use NPM今回自分はVue 3とYarnを選択
? Successfully created project app. ? Get started with the following commands: $ yarn servedocker-composeに以下の部分を足して、サーバーが立ち上がるか確認してみる
command: > ash -c "yarn install && yarn serve"立ち上げ
⛄ docker-compose up sample-front | App running at: sample-front | - Local: http://localhost:8080/ブラウザで以下のURLを叩いて確認してみると...
http://localhost:8080/
- 投稿日:2020-11-16T22:21:38+09:00
Vue.jsでObnizを操作する基本-単純Lチカ(メモ)
Vue.jsからのObniz操作でエラーになったのでメモ。Webアプリでボタン押下でLEDを点灯。
Consoleエラー
原因
- "obniz.onconnect"内で処理が必要? ※Vue.jsでは良くないらしい
デバイスへの接続 - obniz公式var obniz = new Obniz('1234-5678'); obniz.onconnect = async function() { // **** 実行する処理 **** }
- Vue.js での書き方が悪かった ※Vue.jsでは以下のほうが良さそう
Vue.jsでobnizをつかおう - Qiita
if (obniz.connectionState === "connected") { // **** 実行する処理 **** } else { obniz.on('connect', () => { // **** 実行する処理 **** })
- コールバック関数、アロー関数のメモ
JavaScriptの「コールバック関数」とは一体なんなのか
JavaScript アロー関数を説明するよ - Qiita
書き方で変わる?! Vue.jsでthisのスコープを調査した修正後のコード
.html<!DOCTYPE html> <html lang="jp" > <head> <meta charset="UTF-8"> <title>Obniz Test</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <!-- 全体をVue.js有効にする --> <div id="app"> <!-- タイトル --> <h1>Obniz Test</h1> <!-- 設定 --> <h5>Obniz ID</h5> <input v-model:value="ObnizID[0]" type="text" maxlength="4"> <label>-</label> <input v-model:value="ObnizID[1]" type="text" maxlength="4"> <!-- LED-ON-OFF --> <button v-on:click="PowerON">LED-ON</button> <button v-on:click="PowerOFF">LED-OFF</button> </div> <!-- CDN --> <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js'></script> <script src='https://unpkg.com/obniz@3.9.0/obniz.js'></script> <!-- 実行script --> <script src="./script.js"></script> </body> </html>script.jslet obniz; // Obniz関数 // Obniz呼び出し関数 const connect = function(func, ob){ console.log(ob.connectionState); // Obnizへの接続を確認 if (ob.connectionState === "connected") { func(); } else { ob.on('connect', () => { func(); }) } } const app = new Vue({ el: '#app', // Vueが管理する一番外側のDOM要素 data: { // Vue内部で利用する変数定義 ObnizID: ['0000', '0000'], }, methods: { // 関数はココに記述 PowerON: function() { // LED ON // Obniz ID 指定 let obnizid = `${this.ObnizID[0]}-${this.ObnizID[1]}`; this.obniz = new Obniz(obnizid); console.log(obnizid); let me = this; // thisを関数内で使えないので変数に代入 // connect関数を呼んで、connect関数内で以下のFunctionを実行 connect(async function() { const led = me.obniz.wired('LED', { anode: 0, cathode: 1 }); me.obniz.display.clear(); me.obniz.display.print('ON'); led.on(); // LED点灯 }, this.obniz); }, PowerOFF: function() { // LED OFF // Obniz ID 指定 let obnizid = `${this.ObnizID[0]}-${this.ObnizID[1]}`; this.obniz = new Obniz(obnizid); console.log(obnizid); let me = this; // thisを関数内で使えないので変数に代入 // connect関数を呼んで、connect関数内で以下のFunctionを実行 connect(async function() { const led = me.obniz.wired('LED', { anode: 0, cathode: 1 }); me.obniz.display.clear(); me.obniz.display.print('OFF'); led.off(); }, this.obniz); }, }, });
- 投稿日:2020-11-16T21:40:42+09:00
[Vue.js]v-bind
v-bindでGoogleへのlinkつくってみる
js data:{ //htmlに挿入するurlをdataの中に入れておく url:'https://www.google.com/?hl=ja'//これでGoogleへのリンクが貼られる <a v-bind:href = "url">google</a>Googleへのリンク以外にもクラスやidなどまとめて表示させたい場合
js data: //まとめてgoogleオブジェクトをつくる google:{ href:'https://www.google.com/?hl=ja', id:12, class:'goo' }html <a v-bind = 'google'>google</a>href="https://www.google.com/?hl=ja" id="12" class="goo">google
検証画面で見ると上のようになっている(aタグが本当はある)
ちゃんとhref属性とidとclassがまとめてaタグの中に入ってます
- 投稿日:2020-11-16T21:09:01+09:00
[Vue.js]methodsを使う
簡単なmethodを使う
js new Vue({ data:{ }, methods:{ //SayHi!!!と言うメソッドを作る SayHi:function(){ return 'SayHi!!!' }html //SayHi!!!と表示される <p>{{sayHi()}}</p>dataから呼び出したものをメソッドに使う
data:{ message:'hello' } SayHi:function(){ //クォテーションをつけない、thisをつけないとアクセスできない return this.message; }これでhelloを呼び出すことができる
- 投稿日:2020-11-16T20:45:15+09:00
Hello Vue.js 初心者が学んでみた
javascript初心者がVueを学んでいく
まず自分のレベルはjavascriptの基礎を覚えたか覚えてないかくらいの初心者なので的外れなことも多々あるかもしれないのでご注意ください。
//html <body> //Hello Vue.jsと表示させてみる</h1> <div id="app"> //普通にかくとこう <p>Hello Vue.js</p><script> //vueインスタンスを作る new Vue({ //elでhtmlのどこを対象にするかを指定する。 el:'#app', //dataには色々なものを定義できる。 ここではHello Vue.jsと表示させたいのでmessage は Hello Vue.js だよーというのを指定 data:{ message:'hello Vue.js' }このmessageに入れたのを使うにはhtmlに指定してやる必要がある
//{{}}これにさっき作ったmessageを入れてやる <p>{{message}}</p>こうするとHello Vue.jsと表示することができる
ちなみにこれは v-textという物を使っても表現することができる
html //これでも同じくHello vue.jsというのが呼び出せる <p v-text = 'message'></p>
- 投稿日:2020-11-16T20:43:23+09:00
Android 11以降でWebViewでローカルHTMLが表示できないとき
※本記事は、NativeScript-Vueのコードを提示していますが、考え方は、どの開発言語・フレームワークでも同一と思われます。予めご了承ください。
陥った事象
最近、NativeScript-Vueというものを使って、Androidネイティブアプリケーションを試しに作ってみたりしています。Vue.jsに慣れている人であれば、楽にネイティブアプリを作ることができるということで、使わせてもらっています。
さて、開発をしている最中に、UIコンポーネントの1つである「WebView」を使って、アプリ内のアセットとして配置しているHTMLファイルを表示させたい場面がありました。
通常であれば、NativeScript-Vueの場合、次のように書きます。
./src/components/App.vue<template> <Frame> <Page> <GridLayout columns="*" rows="*"> <!-- ↓ここでWebViewコンポーネントを配置して、srcとしてassetsディレクトリ内のファイルを指定 --> <WebView row="0" col="0" src="~/assets/index.html" /> </GridLayout> </Page> </Frame> </template>しかしこの状態で、アプリをAndroid 11上で動作させると、次のような「ERR_ACCESS_DENIED」という表示になってしまいました。エミュレータでも実機でも同様です。
そして、試しにAndroid 10のエミュレータで動作確認すると、正常に表示されるのです。
解決方法
Androidのリファレンスに次のようなことが書かれていました。
setAllowFileAccess
The default value is true for apps targeting Build.VERSION_CODES.Q and below, and false when targeting Build.VERSION_CODES.R and above.
バージョンコードR(つまりAndroid 11)から、WebSettingsのAllowFileAccessの設定が、デフォルトで
false
になっていますよ、とのことです。ですので、明示的にtrue
にしてあげることで、解決できそうです。NativeScript-Vueの場合、次のように、Loadedイベントと組み合わせることで、解決できました。
./src/components/App.vue<template> <Frame> <Page> <GridLayout columns="*" rows="*"> <!-- ↓ここでWebViewコンポーネントを配置して、loadedイベントを捕捉 --> <WebView row="0" col="0" @loaded="webViewLoaded" /> </GridLayout> </Page> </Frame> </template> <script lang="ts"> export default { methods: { // loadedイベントが発生した時の処理 webViewLoaded(args) { if (args.object.android) { args.object.android.getSettings().setAllowFileAccess(true); // ここで、setAllowFileAccessメソッドを使って、trueにする args.object.src = "~/assets/map/index.html"; // 上記設定をしてから、ファイルを初めて読み込む } }, }, }; </script>ただ、同リファレンスにも少し書かれているのですが、このような方法でHTMLを表示させるよりも、より安全な方法があるのかもしれません。
※結局自己解決したのですが、もともとStackOverflowで質問していました。
- 投稿日:2020-11-16T19:24:33+09:00
親から孫コンポーネントのデータ連携方法
概要
vue.jsとtypescriptでアプリを制作中、親-子コンポーネントのデータ連携はできたが、親-子-孫コンポーネントのデータ連携に少し時間がかかってしまった。
そこで、階層の深いコンポーネント間のデータ連携についてまとめていきます。
親クラス
Parent.vue<template> <!-- 1, 2 --> <Child :name="name" @nameFromChild="name=$event"> </Child> </template> <script lang="ts"> import {Vue, Component} from 'vue' import Child from 'components/Child.vue' @Component({ components: { Child }, }) class Parent extends Vue { /** 名前(変更対象) */ private name = ""; } </script>
- Childコンポーネントに空のname=""を渡す
- 子コンポーネントが"nameFromChild"で発火したイベントを受け取り、name変数に変更された値が入る
子クラス
Child.vue<template> <!-- 2, 3 --> <GrandChild :grandChildName="childName" @grandChildName="childName = $event"> </GrandChild> </template> <script lang="ts"> import {Vue, Component} from 'vue' import Child from 'components/Child.vue' @Component({ components: { Child }, }) class Child extend Vue { /** 1 */ @Prop() private name = ""; /** 3 */ get childName(){ return this.name; } /** 4 */ set childName(name: string){ this.$emit('nameFromChild', name); } } </script>
- 親コンポーネントからProp関数で空のname=""を受け取る
- GrandChildコンポーネントに空のchildName=this.nameを渡す
- 孫コンポーネントが"nameFromGrandChild"で発火したイベントを受け取り、childNameに変更された値が渡される
- 孫コンポーネントからgrandChildNameでイベントが発火される。childNameが孫から渡された値($event)によって変更された場合、下記ではemit関数で親コンポーネントにイベントを発火し、書き換えられたnameを渡す
孫クラス
GrandChild.vue<template> <v-text-field :value="grandChildName" @input="$emit('nameFromGrandChild', $event)"> </v-text-field> </template> <script lang="ts"> import {Vue, Prop} from 'vue' class GrandChild extends Vue { /** 1 */ @Prop() private grandChildName?: string; } </script>
- 子から渡ってきた空のgrandChildName=""
- emit関数を使用し、テキストフィールドが変更(input)されたら、変更された値($event)を引数を持ってイベントを発火
- 投稿日:2020-11-16T16:54:02+09:00
3年間数学に触れていない大学生がセンター数学で9割を目指したことがきっかけで習慣継続アプリを作った話。【個人開発】
こんにちは、かしわ(@kasiwa9494)と申します。
1年前にプログラミングを勉強し始めて、今回、個人開発を継続していくためのアプリを作成しました。
何を作ったのか?
タテミチ
目的を達成するまでのメモを残せるWebサービスです。自分だけのプロジェクトを簡単に作成できます。
習慣を継続するためのアプリ
— かしわ (@kasiwa9494) November 16, 2020
「タテミチ」を作りました!
毎日読書をする、
CSSアニメーションを極める
等のプロジェクトがあります。https://t.co/ypmHqGw7swなぜ、作ったのか?
3ヶ月前、友達と「3年間数学に触れていない文系大学生(数学受験)がどれくらいセンター数学で点数が取れるのか」という企画を行っていました。
1日目、数学1A25点という結果で、時間が経てば、人間の記憶は
薄れていくものだと、実感させられました、、、
2週間後、毎日、過去問を解くことを継続することで、
センター数学の解き方の勘と基礎知識を思い出し、数学1A77点を取ることができました!!!
結果的にみると、2~3週間で70~80点台は叩き出すことができました。
しかし、9割は難しかったですこの経験により、「友人に自分が習慣にしたいことを共有し、
反応をもらえると、めちゃくちゃ嬉しい」
ということに気付きました。
よって、習慣を続けさせるシステムをベースとしたWebサービスを作れたら良いなと思い、
今回、作成しました!!!どうやって、作ったのか?
使った技術
Nuxt.js
Netlify上でホスティングしています。
SPAで作っています。Firebase
データベースとしてFirebase FireStore,
認証としてFirebase Authentication,
OGP用の画像を保存するために,FirebaseStorageを利用しています。Netlify
SPAで動的ページのOGPを使えるようにするために
Netlifyのプレレンダリング機能を活用しています。めちゃくちゃ便利です。
TypeScript
コンポーネント間のデータの受け渡しで
どういう型か判断でき、コードが見やすくなりました。今まで、手を出すのが面倒でしたが、
使ってみると、快適です。最新の投稿を検知
firestoreに投稿を保存すると、通知が出るように設定しています。UX的に適切かどうか分かりませんが(勉強不足)、
個人的に欲しいと思ったので、実装しました。動的OGPを実装
これから、毎日読書をしていくことで、どのような効果が出るのか検証してみます。https://t.co/PWOf6LddxS
— かしわ (@kasiwa9494) November 16, 2020CSSアニメーションがカッコいいという動機でとりあえず継続してみます。https://t.co/CyqP8MjASt
— かしわ (@kasiwa9494) November 16, 2020SPAでも、コンテンツに応じてOGP画像を出力できるNetlifyのPrerenderingの機能を利用しています。
これにより、JavaScriptで設定したmetaタグ、OGP画像がTwitter,Facebookで表示できるようになりました。(動的OGPの実装)
どのくらいの期間で作ったのか?
約2週間。
作業時間としては、60~80時間ぐらいだと思います。今後の展望は?
アップデートとしては、
・拍手ボタン(応援)を作る。
・デザインを改善する
など考えています。今回の振り返り
Nuxt + TypeScriptを初めて、個人開発で利用しました。
TSのおかげでコードを快適な環境でかけたので、
今後もTypeScriptを利用していきたいです。これからの個人開発の目標としては、
Webサービスを作る工程を最適化し、3日でサービスを公開できるようにすることです。どうしても、Webサービスを作るという作業に億劫になってしまうので、
今回作った「タテミチ」を活用して、モチベーションをキープできるようにしたいです。今、行っているプロジェクト
CSSアニメーションがカッコいいという動機でとりあえず継続してみます。https://t.co/CyqP8MjASt
— かしわ (@kasiwa9494) November 16, 2020
読書する習慣をつける | 継続するならタテミチ
CSSアニメーションを極める | 継続するならタテミチ
料理スキルを身に付けるために、個人開発でクッキングアプリを作る。| 継続するならタテミチぜひ、プロジェクトを始めてみてください
ここまで読んでくれた方へ
以上、習慣を継続するためにwebサービスを作った話でした。
ここまで読んでくださりありがとうございました。
いいねやコメント、SNSでの共有等をしてくださると、めちゃくちゃ嬉しいです。
良かったら、ツイッター(@kasiwa9494)フォローしてください。
- 投稿日:2020-11-16T14:58:28+09:00
Vue.js で googleMap に overlay view を表示するコンポーネントを作る
google.maps.OverlayViewを継承する用クラス
GoogleOverlay.tsexport class GoogleOverlay { lat: string | number lng: string | number drawable: boolean = true div: HTMLDivElement | null className: string = '' google: any innerHtml: string updateClass: (className: string) => void updateHtml: (html: string) => void active: () => void inactive: () => void // extend google.maps.OverlayView getProjection: any getPanes: any setMap: any draw: () => void remove: () => void constructor( google: any, map: any, lat: string | number, lng: string | number, innerHtml: string, className: string = '', events: { click?: () => void } = {} ) { this.lat = lat this.lng = lng this.div = null this.google = google this.innerHtml = innerHtml this.className = className this.remove = () => { if (!this.div) return ;(this.div.parentNode as Node).removeChild(this.div) this.div = null } this.draw = () => { this.remove() if (!this.drawable) return const projection = this.getProjection() if (!projection) return const point = projection.fromLatLngToDivPixel( new this.google.maps.LatLng(this.lat, this.lng) ) this.div = document.createElement('div') this.div.className = this.className this.div.innerHTML = this.innerHtml this.div.style.left = point.x + 'px' this.div.style.top = point.y + 'px' const panes = this.getPanes() panes.overlayMouseTarget.appendChild(this.div) google.maps.event.addDomListener(this.div, 'click', () => { events.click && events.click() }) } this.updateHtml = (html: string) => { this.innerHtml = html this.draw() } this.updateClass = (className: string) => { this.className = className this.draw() } this.active = () => { this.drawable = true this.draw() } this.inactive = () => { this.drawable = false this.remove() } this.setMap(map) } }GoogleMapにOverlayViewを表示する用のコンポーネント
GoogleMapOverlayView.vue<template> <div v-show="false"> <slot /> </div> </template> <script lang="ts"> import { Component, Vue, Prop, Watch } from 'vue-property-decorator' import { GoogleOverlay } from '../../lib/googleMap' @Component export default class GoogleMapOverlayView extends Vue { @Prop() private google!: any @Prop() private map!: any @Prop() private center!: { lat: number; lng: number } @Prop() private active!: boolean overlay: GoogleOverlay | null = null html: string = '' @Watch('active') setOrRemove() { if (this.active) { this.overlay ? this.overlay.active() : this.setOverlay() return } this.overlay && this.overlay.inactive() } mounted() { this.setOrRemove() } updated() { if (!this.overlay || !this.$el) return if (this.html === this.$el.innerHTML) return this.overlay.updateHtml(this.$el.innerHTML) this.html = this.$el.innerHTML } setOverlay() { GoogleOverlay.prototype = new this.google.maps.OverlayView() this.overlay = new GoogleOverlay( this.google, this.map, this.center.lat, this.center.lng, this.html, 'google-map-overlay-view', { click: this.handleClick } ) } handleClick() { this.$emit('click') } } </script>使用例
<GoogleMap :zoom="17" :center="center" :height="240" > <template slot-scope="scope"> <GoogleMapOverlayView v-for="overlay in overlays" :key="overlay.key" :center="overlay.latLng" :google="scope.google" :map="scope.map" @click="handleSelectOverview(hotel)" > <div>overlayView</div> </GoogleMapOverlayView> </template> </GoogleMap>
- 投稿日:2020-11-16T14:43:01+09:00
コンポーネントに、リンクは一つまで【2020/11/16】
SNSで、今月のおすすめ記事、のようなものを作るときは、投稿いくつかまとめて、その投稿ひとつひとつがリンクを持っている。
この場合は、
1. organism = 今月のおすすめ記事
2. molecule = 各々の投稿 <= routerLinkをひとつ持つとすると、見通しが良くなる
- 投稿日:2020-11-16T13:22:47+09:00
Vueでお絵かき機能を実装
ポートフォリオで写真をクロッピングし、絵を書いたり、フィルターを掛けたり、テキストを描画したりできる機能を実装したので、復習をかねて記事にする。
こちらの方のサイトを例に作成させて頂きました。drawing.vue<template> <div> <div> <canvas ref="canvas" v-bind="attr" @mousedown="dragStart" @mouseup="dragEnd" @mouseout="dragEnd" @mousemove="draw"></canvas> //スマホはこれ @touchstart="dragStart" @touchend="dragEnd" @touchmove="draw" </div> <div id="tool-area"> <v-btn @click="context.globalCompositeOperation = 'source-over';mode = true" :color="mode ? 'red' : 'black'">ペン</v-btn> <v-btn @click="context.globalCompositeOperation = 'destination-out';mode = false" :color="!mode ? 'red' : 'black'">消しゴム</v-btn> <!-- globalCompositeOperationをdestination-outにしないとただ背景を白で塗りつぶすことになる。 <v-btn @click="clear">クリア</v-btn> </div> <div> <!-- v-modelで常に色を双方向データバインディング --> <v-color-picker v-model="penColor"></v-color-picker> <!-- 色と同様ペンの太さを双方向データバインディング --> <v-slider v-model="lineWidth" ticks="always" max="20" thumb-label="always"></v-slider> </div> </div> </template> <script> export default { data() { return { attr: { width: '500px', height: '500px', }, context: null, isDrag: false, penColor: '#000000', lineWidth: 10, mode: true, } }, watch: { penColor(){//ペンの色が変わればcanvasのコンテキストに反映される this.context.strokeStyle = this.penColor; }, lineWidth(){//ペンの太さがが変わればcanvasのコンテキストに反映される this.context.lineWidth = this.lineWidth; } }, mounted(){ //canvasの初期設定 const canvas = this.$refs.canvas; this.context = canvas.getContext('2d') this.context.lineCap = 'round'; this.context.lineJoin = 'round'; this.context.lineWidth = this.lineWidth; this.context.strokeStyle = this.penColor; methods: { // 描画開始(mousedown) dragStart(e) { const x = e.layerX//canvas内のx座標を取得 const y = e.layerY//canvas内のy座標を取得 this.context.beginPath(); //パスをリセット。これがないとクリックした場所から最初クリックした場所に毎回ラインが走る。 this.context.lineTo(x, y); this.context.stroke(); this.isDrag = true; }, // 描画 draw(e) { const x = e.layerX const y = e.layerY if(!this.isDrag) { return; } this.context.lineTo(x, y); this.context.stroke(); }, // 描画終了(mouseup, mouseout) dragEnd() { this.context.closePath(); this.isDrag = false; }, clear() { this.context.clearRect(0, 0, this.attr.width, this.attr.height); //canvasのwidthとheightを入れると全体がリセットされる。 }, } } </script>canvas.getContext('2d')でcanvasの環境を操作できるようになるという認識。
なおcontextは初期状態で以下のような設定になっている。{ direction: "ltr" fillStyle: "#000000" filter: "none" font: "10px sans-serif" globalAlpha: 1 globalCompositeOperation: "source-over" imageSmoothingEnabled: true imageSmoothingQuality: "low" lineCap: "butt" lineDashOffset: 0 lineJoin: "miter" lineWidth: 1 miterLimit: 10 shadowBlur: 0 shadowColor: "rgba(0, 0, 0, 0)" shadowOffsetX: 0 shadowOffsetY: 0 strokeStyle: "#000000" textAlign: "start" textBaseline: "alphabetic" }これらの値を変えるとどうなるか調べて使ってみよう。
なお、今回使ったのはfillStyle、globalCompositeOperation、lineCap、lineJoin、lineWidthである。
- 投稿日:2020-11-16T12:27:53+09:00
Vue + Electron の NodeIntegration でハマった話
環境について
@vue/cli: 4.5.8
vue: 2.6.11
electron: 9.0.0vue add electron-builder でプロジェクト作成。
Typescrtipt使用。あと、関係あるかは分かりませんがvuetify(2.2.11)も使用。起こった症状
ipcRenderer を ブラウザ側でimport使用とすると、fs.existsSync is not a function とエラーが発生し、ページが描画されない。
もちろん、webPreference の nodeIntegration は true にしてあります。
対処法
vue-cli-plugin-electron-builderのissueで解決したという人がいたため、そのリンク先であるElectronのissue を見に行きます。
すると、require 周りでエラーが出ているのでラップするとか、preloadにipcRendererを入れるといいとか書いてあります。
でも前者はどこを直すかよくわからないし、後者はTypescrtiptを使っていると、windowにプロパティを足すのにいろいろと手間が必要……
なのでもう少し探してみることにしました。解決
上記のissueの下のほうにありました。
vue.config.js をいじる方法です。vue.config.jsmodule.exports = { "transpileDependencies": [ "vuetify" ], pluginOptions: { electronBuilder: { nodeIntegration: true } } }このpuluginOptionsを追加したところ、無事にエラーが消えてビルドできるようになりました!
めでたしめでたし。
- 投稿日:2020-11-16T03:15:47+09:00
Vue.jsを使って簡単なカウンターアプリを作ってみた
最近Vue.jsの勉強を本格的に始めました。ひとまず何か簡単なものを作ろう!ということで、今回はカウンターアプリを作ってみました。良ければお試し下さい→カウンターアプリ
実現したいこと
1.ボタンをカチカチして数値を変更し、計算させる。
2.計算方法は足し算、引き算、掛け算、割り算を用意する。
3.計算方法の表記は、切り替えたタイミングで上に表示させる。コード
index.html<!DOCTYPE html> <html lang="jp"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>カウンターアプリ</title> <link rel="preconnect" href="https://fonts.gstatic.com"> <link href="https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&display=swap" rel="stylesheet"> <link rel="stylesheet" href="style.css"> </head> <body> <div id="app"> <div id="container"> <h1 class="title">{{title}}</h1> <div class="inputArea"> <div class="top"> <button class="btn" @click="firstIncrement">+</button> <button class="btn" @click="secondIncrement">+</button> </div> <h1 class="cal">{{first}} {{key}} {{second}} = {{resultAdd(key)}}</h1> <div class="bottom"> <button class="btn" @click="firstDecrement">-</button> <button class="btn" @click="secondDecrement">-</button> </div> </div> <div class="format"> <button class="changeBtn" @click="key = '+'">+</button> <button class="changeBtn" @click="key = '-'">-</button> <button class="changeBtn" @click="key = '×'">×</button> <button class="changeBtn" @click="key = '÷'">÷</button> <button class="changeBtn" @click="first = 0, second = 0">C</button> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> <script src="main.js"></script> </body> </html>style.css*{ margin: 0; padding: 0; font-family: 'Oswald', sans-serif; touch-action: manipulation; } body{ color: white; background-color: black; } #container{ height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center; } button{ color:black; background-color: white; outline: none !important; cursor: pointer; } .title{ font-size: 45px; margin-bottom: 60px; } .cal{ font-size: 50px; text-shadow: 3px 3px rgb(121, 121, 121); } .inputArea{ width: 100%; height: 250px; display: flex; flex-direction: column; justify-content: space-around; align-items: center; margin-bottom: 60px; & .btn{ font-size: 30px; font-weight: 700; padding: 5px 10px; margin: 20px; } & .top, .bottom{ margin-right: 70px; } } .changeBtn{ font-size: 30px; font-weight: 700; padding: 5px 10px; margin: 0px 10px; }main.jsnew Vue({ data:{ first:0, second:0, sum:0, title:'addition', format:['Addition','Subtraction','Multiplication','Division'], key:'+', }, methods:{ firstIncrement(){ this.first += 1; }, firstDecrement(){ if(this.first > 0){ this.first -= 1; } }, secondIncrement(){ this.second += 1; }, secondDecrement(){ if(this.second > 0){ this.second -= 1; } }, }, computed:{ resultAdd(){ return function(f){ if(f === '+'){ this.title = this.format[0]; return this.first + this.second; }else if(f === '-'){ this.title = this.format[1]; return this.first - this.second; }else if(f === '×'){ this.title = this.format[2]; return this.first * this.second; }else{ this.title = this.format[3]; this.sum = this.first / this.second; return Math.round(this.sum * 1000) / 1000; } } }, }, }).$mount("#app");methodsプロパティ
+ボタン、-ボタンをクリックすると、methodsプロパティのIncrementメソッド、Decrementメソッドが発火します。メソッド内ではdataプロパティに設定したfirstプロパティとsecondプロパティを参照し、値を加算、減算します。
メソッドからdataプロパティを参照する時はthisを忘れずに(よく忘れてエラーになります・・・)computedプロパティ
computedプロパティのresultAddではfirstやsecondの変更を検出して計算結果を返してくれます。
さらに今回は計算方法が4パターン欲しいので、resultAddに引数を持たせて、条件分岐をさせてみました。例えば渡された引数の文字列が「+」だったら、足し算の結果を返す。「×」だったら、掛け算の結果を返す。という感じです。また、計算方法の変更は、下の「+」「-」「×」「÷」のボタンで変更しますが、これらのボタンが押された際も、resultAddが発火し、表記の変更をしつつ、変更した方法で計算結果を返してくれます。(computed便利!)
割り算で四捨五入
割り算で割り切れない場合、結果が「3.33333333・・・」という感じで表示され、レイアウトが大変なことになるので、今回はMath.round関数を使って、小数点第四位を四捨五入しています。
作ってみて
という感じで、簡単なカウンターアプリを作ってみました。
JavaScriptと比べるとVue.jsはコードが短く、簡潔に記述できるので、(もっと簡潔に書けるかもしれませんが、、)改めてフレームワークすご!!と思いましたね。引き続きVue.js頑張りたいと思います!