20210727のvue.jsに関する記事は4件です。

Nuxt.jsでpdf.jsを使うときにハマったこととその解決策

Nuxt.jsでpdf.jsを使おうとしたらいくつか困るポイントがあり、またドンピシャな解決策もなかなか見つからなかったので備忘録的に残しました。 体系だった使い方は、参考にあげたGoodpatchさんの記事がよくまとまっています。 しかし、この記事通りにやってもハマると思うので、合わせて読むと良いと思います! ちなみに、この段階で私が使っていたNuxtのバージョンは2.15.7です。 また、pdf.jsはnpmでインストールできるpdfjs-distを使っています。 pdfjs-distのバージョン この記事を書いている時点で最新のpdfjs-distのバージョンは2.9.359ですが、新しいバージョンでは新しいJavascriptの記法をつかっているということだと思われ、pdf.jsが呼ばれるタイミングでSyntax Errorが起きてしまいます。 WebpackやBabelに精通しているわけではないので深追いはせず、pdfjs-distのバージョンをもどすのが手っ取り早いと思い2.5.207に戻すことで対処しました。 CMap、worker pdf.jsでPDF内の文字を表示させるには、CMapが必要です。 また、こちらは絶対必要というわけではないですが、パフォーマンス的に処理をメインスレッドから逃すためにWeb Workerを使うためのスクリプトも使うことができると望ましいです。 ブラウザがこれらのファイルを読みにいけるようになっている必要があります。Nuxtを使っている場合は、staticディレクトリの中に配置してしまうのが手っ取り早いと思います。(参考で挙げたように、クロスオリジン関連には気をつけましょう) これらはnode_modules/pdfjs-dist/のなかに含まれているので、 cp -r node_modules/pdfjs-dist/cmaps/ static/cmaps/ cp node_modules/pdfjs-dist/build/pdf.worker.min.js static/ とstatic/の中にコピーしておいて、コンポーネントの中でそれぞれの位置を指定します。 <template> ... </template> <script> import * as PDFJS from 'pdfjs-dist' PDFJS.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js' // ← workerスクリプトを配信するパスを指定 export default { ... async mounted() { // 別にmountedである必要はないです this.pdf = await PDFJS.getDocument({ data: <PDFファイルのデータ>, cMapUrl: '/cmaps/', // ←ここでCMap関連のファイルを配信するパスを指定 cMapPacked: true }).promise }, ... } </script> CMapについて詳しくは↓ レンダータスクのキャンセル 最初はこんな感じで、表示するページを表すthis.currentPageNum が変化するたびに同じcanvasを使いまわして新しいページを表示するようにしていました。 参考のGoodpatchさんの記事と同じ内容です。 以下はmethodsの中に書くメソッドです。 async renderPage() { const page = await this.pdf.getPage(this.currentPageNum) const canvas = this.$refs.previewZone const viewport = page.getViewport({ scale: 1 }) const context = canvas.getContext('2d') const renderingTask = page.render({ canvasContext: context, viewport: viewport, }) await this.renderingTask.promise }, だいたいこれで動くのですが、ページ切替を早く行うとpdfjs Cannot use the same canvas during multiple render() operationsというエラーが起きていました。 まだ前のrenderが終わっていないのに次のrenderが呼ばれるとダメなようです。 そこで、renderingTaskをrender処理が終わっていない間はコンポーネントのプロパティに持たせるようにして、次のrenderが来たときに前のが終わっていなかったらキャンセルするようにしました。 async renderPage() { if (this.renderingTask) { await this.renderingTask.cancel() this.renderingTask = null } const page = await this.pdf.getPage(this.currentPageNum) const canvas = this.$refs.previewZone const viewport = page.getViewport({ scale: 1 }) const context = canvas.getContext('2d') this.renderingTask = page.render({ canvasContext: context, viewport: viewport, }) this.renderingTask._internalRenderTask.callback = () => { this.renderingTask = null } await this.renderingTask.promise }, 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascriptで扱う連想配列のあれこれ(GET / CREATE系)

はじめに 連想配列であんなことやこんなことをしたい人向けのきじになります。 バックエンドで整形して返すのが一番ですが、javascriptで処理したいという方は参考までに。 (GET系)連想配列から特定の値を含む配列を取得 index.js var array = [ {id:1, name:"hoge",price:3000, status:1}, {id:2, name:"test",price:300, status:1}, {id:3, name:"hello",price:1500, status:1}, {id:4, name:"world",price:3000, status:2}, {id:5, name:"hoge",price:200, status:1}, {id:6, name:"test",price:400, status:1}, {id:7, name:"hoge",price:4000, status:2} ]; // 1つの検索条件で取得 var select_id = 3; const callback = item => item.id == select_id; // 検索条件 var result = array.filter(item => callback(item)); console.log(result); // {id:3, name:"hello",price:1500, status:1} // 複数の検索条件で取得 var select_name = "hoge"; var select_price = 1000; const callback = item => item.name == select_name && item.price >= select_price; var result = array.filter(item => callback(item)); console.log(result); // {id: 1, name: "hoge", price: 3000, status: 1} {id: 7, name: "hoge", price: 4000, status: 2} // 配列内のインデックスを取得(単体) var select_id = 4; const index = array.findIndex(item => item.id === 4); console.log(index); // 3 // 配列内のインデックスを取得(複数) var select_name = "hoge"; var result = []; var exam_array = array; for (var i = 0; i < exam_array.length; i++){ var index = exam_array.findIndex(item => item.name == select_name); // 複数条件は&&でつなげる if(index != -1){ console.log(index); result.push(index); exam_array.splice(index,1,""); } else { console.log("complete"); break; } } console.log(result); // [0, 4, 6] (CREATE系)配列に新しい値を追加 index.js var array = [ {id:1, name:"hoge",price:3000, status:1}, {id:2, name:"test",price:300, status:1}, {id:3, name:"hello",price:1500, status:1}, {id:4, name:"world",price:3000, status:2}, {id:5, name:"hoge",price:200, status:1}, {id:6, name:"test",price:400, status:1}, {id:7, name:"hoge",price:4000, status:2} ]; // 配列の最後に追加 var new_data = {'id':7, 'name':"new_data",'price':5000, 'status':1}; array.push(new_data); console.log(array); // (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}] // 配列の最後に追加(auto_inclement版) var last_id = array[array.length -1].id; var new_data = {'id':last_id + 1, 'name':"new_data",'price':5000, 'status':1}; array.push(new_data); console.log(array); // (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}] <- id:8のitem // 任意の場所に値を追加(ユニークじゃなくてもいい場合) var put_position = array[5 - 2]; // 前から5番目に追加したい場合,先に4番目の配列(直前の配列)を取得する var put_id = put_position.id; var new_data = {'id':put_id + 1, 'name':"new_data",'price':5000, 'status':1}; array.splice(put_id,0,new_data); console.log(array); // ...{id: 4, name: "world", price: 3000, status: 2} // {id: 5, name: "new_data", price: 5000, status: 1} // {id: 5, name: "hoge", price: 200, status: 1} // {id: 6, name: "test", price: 400, status: 1}... // 任意の場所に値を追加(後の値が自動調整版) var put_position = array[5 - 2]; // 前から5番目に追加したい場合,先に2番目の配列(直前の配列)を取得する var put_id = put_position.id; // 直前の配列のidを取得する var new_data = {'id':put_id, 'name':"new_data",'price':5000, 'status':1}; array.splice(put_id,0,new_data); var exam_array = array; const new_index = exam_array.findIndex(item => item.id === new_data.id); var before_array = exam_array.slice(0,new_index + 1); var adjust_array = exam_array.slice(new_index + 1, exam_array.length); for(var j = 0; j < adjust_array.length; j++){ adjust_array[j].id = adjust_array[j].id + 1; } var update_array = before_array.concat(adjust_array); array = update_array; console.log(array); // ...{id: 4, name: "world", price: 3000, status: 2} // {id: 5, name: "new_data", price: 5000, status: 1} // {id: 6, name: "hoge", price: 200, status: 1} // {id: 7, name: "test", price: 400, status: 1} // {id: 8, name: "hoge", price: 4000, status: 2}... 次回はDELETEとUPDATEも紹介します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure Static Web Appsで短時間でWEBアプリを公開する

前置き 2021年 5月にAzure Static Web Appsが正式にGA(一般公開)されました。 私は普段よく業務でVue.jsを使っているのですが、Azureでホスティングする際、今まではストレージアカウントのBlob StorageやApp Serviceを利用していましたが、この度専用のサービスがリリースされるということで使い方を試してみました。 前提条件 本記事ではVue.jsを使用してWebアプリケーションを構築します。 また、素早くアプリケーションを構築するためVue CLIを使用します。 バージョン管理ツールはGitHubを使用します。 それぞれのバージョンについては下記の通りです。 Vue.js:2.6.14 Vue CLI:4.5.13 npm:7.18.1 Azure Static Web Appsとは Azure Static Web Apps は、GitHubやAzure DevOpsのリポジトリから Webアプリケーションを自動的にビルド&デプロイするサービスです。 主要な機能は以下の通りです。 HTML、CSS、JS、画像等の静的コンテンツのWebホスティング リポジトリの変更によってビルドとデプロイがトリガーされるGitHub統合およびAzure DevOps統合 Azure Functionsとの統合を標準サポート APIの呼び出し時のCORSの構成が不要 リポジトリの変更をトリガーにビルドからデプロイまで実行されるCI/CD環境を提供 グローバルに分散された静的コンテンツがユーザーに近いリージョンに配置される 自動的に更新される無料のSSL証明書を使用可能 カスタムドメインを設定可能 Azure AD、GitHub、Twitter等の認証プロバイダーとの統合を標準サポート カスタマイズ可能な認可ロールの定義と割り当て 提供するコンテンツとルートを完全に制御できるようにするバックエンド ルーティング規則 プルリク時に、デプロイ前のサイトのプレビュー状態を確認可能 Static Web Appsの構成図 下図はStatic Web Appsの構成図になります。 リポジトリのコード変更をトリガーに、Build&Deployのワークフローが実行されてStaic Web Appsに反映されるイメージです。 WEBアプリケーションをホスティングする まずはWEBアプリのホスティングを試してみます。 GitHubにリポジトリ(リポジトリ名:static-web-apps)を作成する。 ローカルにリポジトリをクローンする。 git clone https://github.com/kdl-minase/static-web-apps.git Vue CLIを使って土台となる環境を準備する。 ※vuetifyは必要であれば追加する。 cd static-web-apps vue create . vue add vuetify npm i 作成した土台をローカルホストで確認する。 npm run serve Vue CLIで作成した土台となるアプリケーション mainブランチにソースをpushする。 git add --all git commit git push origin main Static Web Appsのリソースを作成する。 Azure Functions APIとステージング環境のリージョンはEast Asiaを選択する。 プランはFreeプランを選択する。 「GitHubアカウントでサインイン」ボタンを押下する。 「Authorize Azure-App-Service-Static-Web-Apps」のボタンを押下する 各項目に以下の値をそれぞれ設定する。 組織:リポジトリを作成した組織 リポジトリ:作成したリポジトリ 分岐:main ビルドのプリセット:Vue.js アプリの場所:/ APIの場所(※後で使用します):api 出力先:dist GitHub Actionsのワークフローの状態を確認する。 ワークフローが完了後Static Web Appsの[概要]から発行されたURLを確認する。 正常にアプリケーションが表示されたらホスティング完了です。 Azure Functionsと統合する 次にStatic Web AppsはAzure Functionsとの統合を標準でサポートしているので、 APIを実装してWebアプリと疎通できるか試してみます。 ルート階層でapiディレクトリを作成する。 VsCodeのAzure Functionsの拡張機能を使ってHttpTrigerの関数を作成する。 F1キーでコマンドパレットを開いてcreate new projectからapiディレクトリを指定する。 javascript → HttpTrigger → 関数名入力 → Anonymousの順番で設定を進めます。 今回はGETのAPIのみ作成するので、api/HttpTrigger1/function.jsonのmethodsからpostを削除する。 { "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get", "post" ←削除 ] }, { "type": "http", "direction": "out", "name": "res" } ] } APIのURLの設定のためapi/HttpTrigger1/function.jsonのrouteを設定する。 { "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get" ], "route": "msg" ←追加 }, { "type": "http", "direction": "out", "name": "res" } ] } ※この場合のAPIのurlは/api/msgになる ローカル環境でAPIを実行するために以下の設定を行う ○ api/local.settings.jsonにCORSの設定を追記 "Host": { "CORS": "http://localhost:8080" } ○ vue.config.jsにプロキシ設定を追記 devServer: { proxy: { '/api': { target: 'http://localhost:7071' } } } API実行に必要なライブラリをインストールする npm i vue-axios npm i axios アプリケーション側を編集してAPIを呼び出す処理を追記する main.jsにaxiosのimport設定を追記 main.js import Vue from 'vue' import App from './App.vue' import vuetify from './plugins/vuetify' import axios from 'axios' // 追記 import VueAxios from 'vue-axios' // 追記 Vue.config.productionTip = false Vue.use(VueAxios, axios) // 追記 new Vue({ vuetify, render: h => h(App) }).$mount('#app') HelloWorld.vueの内容を編集してAPIを実行するUIに変更 HelloWorld.vue <template> <v-container fluid> <v-row justify="center"> <v-col cols="4"> <v-card> <v-card-text> <v-row> <v-col cols="12"> <v-text-field v-model="name" outlined hide-details > </v-text-field> </v-col> <v-col v-show="msg" cols="12"> {{ msg }} </v-col> </v-row> </v-card-text> <v-card-actions> <v-btn @click="getMsg" color="primary" dark block > メッセージ取得 </v-btn> </v-card-actions> </v-card> </v-col> </v-row> </v-container> </template> <script> export default { name: 'HelloWorld', data: () => ({ name: '', msg: '' }), methods: { async getMsg () { this.msg = await this.axios.get(`api/msg?name=${this.name}`).then(res => res.data) } } } </script> ローカル環境でAPIが実行可能か確認する。 2つコンソールを起動して片方でnpm run serveを実行してアプリケーションを起動する。 もう片方はapi配下に移動後にfunc startを実行してAPIを起動する。 編集後のアプリケーション テキストボックスにいれた文字列をクエリーに設定して、GETのAPIを実行した結果を画面に表示するアプリケーション mainブランチに編集後のソースをpushする。 GitHub Actionsのワークフローの状態を確認する。 ワークフロー完了後、Static Web Appsの[関数]に追加したAPIが表示されているか確認する。 static web appsの[概要]から発行されたURLを確認する。 ※APIが正しく実行できるかを確認する。 ステージング環境を準備する Static Web Appsでは本番環境にデプロイする前に、 ステージング環境のプレビューURLを発行して動作確認を行うことができるのでこの機能も試してみます。 stagingブランチを作成する git branch staging git switch staging stagingブランチでアプリケーションのソースを変更する。 ボタンの色をピンク色に変更してみます。 HelloWorld.vue <v-btn @click="getMsg" color="pink" ←ボタンの色をピンク色に変更 dark block > メッセージ取得 </v-btn> stagingブランチにソースをpushする。 mainブランチに対するプルリクエストを作成する。 GitHubアクションのワークフローの状態を確認する。 プルリクエストページに表示されるプレビューURLを参照する。 プレビューURLの結果(ボタンの色を変更している) ※Static Web Appsの[環境]からもstaging環境を参照することができます。 価格設定 参考までにStatic Web Appsの価格設定のURLを記載します。 カスタム認証や、SLAが不要であれば基本的には無料枠で必要な機能を試すことが可能です。 Static Web Apps の価格 参考 Azure Static Web Apps のドキュメント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonを使ってリアクティブなWebアプリを作りたい【開発編5】Herokuの開発環境と本番環境

こちらの続きです。 pythonを使ってリアクティブなWebアプリを作りたい【開発編4】パスワードの暗号化 今回は、Flask-Vue.jsの開発で、開発環境と本番環境をどのようにマネージするのかについて書いていきます。 どうやって開発を続けるか 今回のアプリケーションは、開発をローカル環境で行い、本番環境はHerokuにデプロイする形で行います。 HerokuへのデプロイはGithub経由で行うものとします。 何に悩むのか ここで示したのですが pythonを使ってリアクティブなWebアプリを作りたい【開発編2】 Herokuにビルドするにあたって、あらかじめdistフォルダに静的ファイルをビルドしています。その際に、環境変数を読み込んでるんですよね。 つまり、ローカル環境で使っているビルドファイルをそのままHerokuにアップしても使えません。 そこで前回はブランチ分けて使ってねという話をしたのですが、これはこれで開発が面倒です。 そこで、何をどうするかという話です。 ビルド環境を追加しましょう frontend/package.json にビルドコマンドが指定してあるのですが、を少し書き換えます frontend/package.json "build": "cross-env NODE_ENV=development vue-cli-service build --mode development --dest ../dist_dev", "build:prod": "cross-env NODE_ENV=production vue-cli-service build --mode production --dest ../dist", こんな形にします。 これまでは、 $ yarn build すると、ルートディレクトリに distフォルダが作られましたが、これをdist_dev フォルダに変更します。 次に、本番環境用のビルドコマンドを追加します。 $ yarn build:prod とすると、本番環境用のビルドが走るようになり、distフォルダが作られるようになります。 本番環境用のビルド設定ファイルを作る frontend/.env.development というファイルがあると思うのですが、これの本番用ファイルを作ります。 frontend/.env.production frontend/.env.production ENV = 'production' # base api VUE_APP_BASE_API = 'HerokuのURL' これを作ることで、yarn build:prodしたときにこちらの設定ファイルが読み込まれます。 Flaskが見るディレクトリの設定を書き換える Flaskが見ているディレクトリの指定は backend/init.py にかかれているのですが、これを書き換えます。(+の行は追加、-の行は削除) backend/__init__.py + import os - app = Flask(__name__, static_folder='../dist/static', template_folder='../dist') + app = Flask(__name__, static_folder=os.environ["STATIC_FOLDER_PATH"], template_folder=os.environ["TEMPLATE_FOLDER_PATH"]) これでフォルダの指定を環境変数から取ってくる形になりました。 環境変数を追加します ローカル環境は.envに追加します。 本番環境はHerokuのSetting>Config Vars に追加して下さい。 ここでやりましたね export STATIC_FOLDER_PATH="../dist_dev/static" export TEMPLATE_FOLDER_PATH="../dist_dev" ファイルの最下部にこちらを追加すればOKです。 .gitignoreを調整 最後に、本番環境にはローカルように作られた dist_dev は不要ですのでこれを追加します。 + dist_dev ビルド&デプロイ まずはローカル環境でビルドしましょう。 $ cd frontend $ yarn build こちらのコマンドで ルートディレクトリに dist_dev が作成されればOKです。 ルートディレクトリに戻ってFlaskを起動しましょう $ cd ../ $ flask run これで http://localhost:5000/ にアクセスして動いていればOKです。 次に本番環境用のファイルをビルドします $ cd frontend $ yarn build:prod こちらのコマンドでルートディレクトリに dist が作成されていればOK。 今度はGithubにファイルをプッシュしましょう。 $ cd ../ $ git add dist $ git add backend/init.py $ git add frontend/package.json $ git add frontend/.env.production $ git commit -m'本番環境/開発環境の一本化' $ git push -u origin main 最後にHerokuのURLを叩いて無事に稼働しているかの確認をしましょう。 関連リンク pythonを使ってリアクティブなWebアプリをお手軽に1分で作りたい pythonを使ってリアクティブなWebアプリを作りたい【基礎編】 pythonを使ってリアクティブなWebアプリを作りたい【開発編】 pythonを使ってリアクティブなWebアプリを作りたい【開発編2】 pythonを使ってリアクティブなWebアプリを作りたい【開発編3】 pythonを使ってリアクティブなWebアプリを作りたい【開発編3-2】 pythonを使ってリアクティブなWebアプリを作りたい【開発編4】パスワードの暗号化 pythonを使ってリアクティブなWebアプリを作りたい【開発編5】Herokuの開発環境と本番環境←イマココ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む