- 投稿日:2021-03-01T19:08:41+09:00
VueCLI + javascript環境で、WebWorkerを使用する
web workerでの記事は、webpack環境(nuxt.js環境)や、typescriptでの記事が多く存在し、
所々詰まっていたので記事にします。
Web Worker の使用(MDN)
Vue.js で WebWorker を使う
laravel-mix + Vue.js (ES) + WebWorker (TS)
これらの記事を参考にしました。導入
vue ui
等でvueを立ち上げたものとして、
プロジェクト直下で
npm install worker-loader
とし、worker-loaderを導入します。そして、プロジェクト直下の
vue.config.js
(無ければ作成し)に、
下記の内容を記述しますvue.config.jsmodule.exports = { chainWebpack: config => { config.module .rule('worker-loader') .test(/\.worker\.js$/) .use({ loader: 'worker-loader', options: { inline: true } }) .loader('worker-loader') .end() } //... }実行準備
次に、srcフォルダ直下に
workers
というフォルダと、worker1
というjsファイルを作成します。
(※名称はなんでも良いと思います。また、フォルダは存在していなくても良いと思います。)src |-assets |-components |- ... |-workers |-worker1.js |-App.vue |-main.jsこのような構成になるかと思います。
次に、worker1.jsの中身をworker1.jsaddEventListener('message', e => { const { data } = e if (data && typeof data == 'number') { return postMessage(data*data) } else { return postMessage(10) } }) export default {}としてみます。
workerに投げられた変数が、int型の場合、二乗を返し、
それ以外の場合10を返す関数です。次に、実際にvueファイルでworkerを呼び出します。
試しに、vuecliで生成されるHome.vueに書いていきます。Home.vue<script> import Worker1 from 'worker-loader!@/workers/worker1' export default { name: 'Home', components: { }, data () { return { reload: 0 } }, methods: { workerTest: function () { const worker = new Worker1() worker.onmeessage = e => { const { data } = e this.reload = data worker.terminate() } worker.postMessage(20) } } } </script>このようにします。
import文に、worker-loader!
をpath名の前に挿入することに気をつけ、また、
worker.onmessageで、workerの処理が終わった場合(つまりpostMessageが返った場合)の処理を記述します。
今回の場合は、処理が終わり次第、this.reloadに代入し他で参照できるようにします。
また処理を終えたあとにworkerが存在する意味はないので、terminateで削除します。
(※importがlintに怒られるかもしれないので、その場合はruleに記述しましょう...)実行
Home.vue<template> <div class="home"> <button @click="workerTest()">worker!!</button> {{ this.reload }} </div> </template>実際に、このようにして試してみると...
実際に、workerを通して、値が変更されたのがわかります。
また、Home.vueworkerTest: function () { const worker = new Worker1() worker.onmessage = e => { const { data } = e this.reload = data } worker.postMessage(20) }とし、
開発者ツールのSourcesをみると
実際にworkerが立っているのがわかります。other
ループの中で実行
試しに
Home.vueworkerTestLoop: function () { for (let i = 0; i < 10; i++) { const worker = new Worker1() worker.onmessage = e => { const { data } = e this.reload += data worker.terminate() } worker.postMessage(20) } }
- 投稿日:2021-03-01T15:19:54+09:00
Vue3 の nextTick は何か
DOM の更新は非同期に行われる
Vue は 3.x, 2.x に関わらず、非同期に DOM 更新を実行しています。
DOM 更新が非同期であることは、以下の例で確認することができます。<!DOCTYPE html> <html lang="en"> <head> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"></div> <script> const { createApp, nextTick } = Vue const App = { template: ` <div ref="sample"> {{ msg }} </div> `, data() { return { msg: 'initial value' } }, mounted () { this.msg = 'mounted value' console.log('mounted', this.$refs.sample.innerText) // mounted initial value } } createApp(App).mount('#app') </script> </body> </html>
this.msg = 'mounted value'
によって DOM 更新が必要なデータ更新をしていますが、直後に実行されるconsole.log
では、DOM 更新前のデータが出力されています。DOM 更新が同期的ならconsole.log
では、mounted value
が出力されるはずです。
DOM 更新後のデータを確認するためには、DOM 更新をする非同期関数の実行後である必要があります。
nextTick
は、DOM 更新をする非同期関数を全て実行した後に、第1引数として渡された関数を実行します。そのため、nextTick
に渡した関数で DOM を確認すると、DOM が更新されていることが確認できます。<!DOCTYPE html> <html lang="en"> <head> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"></div> <script> const { createApp, nextTick } = Vue const App = { template: ` <div ref="sample"> {{ msg }} </div> `, data() { return { msg: 'initial value' } }, mounted () { this.msg = 'mounted value' nextTick(() => { console.log('nextTick', this.$refs.sample.innerText) // nextTick mounted value }) } } createApp(App).mount('#app') </script> </body> </html>
console.log
では、DOM 更新後のデータが出力されています。nextTick を実装してみる
稀なケースを除き、基本的には DOM 更新をする非同期関数を全て実行した後に、DOM を確認すれば、DOM 更新後のデータを確認することができます。 これはとても簡単で、DOM 更新をする非同期関数より後に実行される非同期関数を実行し、その実行後に DOM を確認するだけです。
<!DOCTYPE html> <html lang="en"> <head> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"></div> <script> const { createApp, nextTick } = Vue const App = { template: ` <div ref="sample"> {{ msg }} </div> `, data() { return { msg: 'initial value' } }, mounted () { const self = this this.msg = 'mounted value' Promise.resolve().then(() => { console.log('promise', self.$refs.sample.innerText) // promise mounted value }) }, } createApp(App).mount('#app') </script> </body> </html>DOM 更新をする非同期関数より後に実行される非同期関数は、
Promise
で実装します。とても簡単ですが、DOM 更新後のデータがconsole.log
で出力されていることが確認できます。まとめ
nextTick について荒くまとめました。
もっと nextTick を理解するには、イベントループ、マクロタスク、マイクロタスクについて理解を深めることが大切です。これらについて知りたい場合、以下の URL は良い助けになると思います。https://javascript.info/event-loop#macrotasks-and-microtasks
https://www.youtube.com/watch?v=8aGhZQkoFbQ
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
- 投稿日:2021-03-01T09:45:23+09:00
vue routerについての話 2021/2/1
今日やること
vue.jsでurlにあるcode以下(クエリパラメーター)の文字をブラウザ上で表示する。
クエリパラメーターとは
まざまな情報をWebサーバーに伝えるためにURLに付け加える情報
今回の場合だと
localhost:8080/?code=AQUAKEOAJ....
色のついている部分がクエリパラメーターである。 ここを表示したいわけである。
まず
Vue.js Devtools
を使うにあたりを導入したい。Vue.js Devtools
Vue.js Devtoolsとは
Vue.js Devtoolsは、Vue.jsの開発をサポートする Chromeブラウザの拡張機能 です。これを導入するとconsoleを開かなくてもdataの中身などを確認することができるようになります。
vue route
導入
マニュアルセットアップ
①yarnでインストールするyarn add @vue-routerパラメータを取得してみる
パラメータの取得は、次のコードで可能です。
:js
this.$route.query.{キー}
{キー}の部分は、今回の例でいうと、code になります。
FBButton<template> <div> <button @click="open">Login with Facebook</button> {{ info }} </div> </template> <script> export default { data(){ return { info:null } }, mounted (){ let code = this.$route.query.code if(code){ this.info = code } } }
DjangoApiプロジェクトを作る
今回はDjangoApiプロジェクトを公式ドキュメントにしたがって進めていく。
djagoをインストールする
pip install djangorestframework pip install django-filter # Filtering support
setting
のINSTALLED_APPS
に'rest_framework'を追加するsettings.pyINSTALLED_APPS = [ ... 'rest_framework', ]次に
urls.py
ファイルを変更する。urls.pyurlpatterns = [ ... path('api-auth/', include('rest_framework.urls')) ]次に
settings.py
の一番下にREST_FRAMEWORKの設定情報を追加します。ここでは標準のパーミッションの設定を追加しています。setting.pyREST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' ] }次に
serializers.py
viewsets.py
ファイルを追加する。serializers.pyfrom django.contrib.auth.models import User from rest_framework import serializers class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ['url', 'username', 'email', 'is_staff']viewsets.pyfrom django.contrib.auth.models import User from rest_framework import viewsets from core.serializers import User Serializer class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer以下のコードを追加する
urls.pyfrom rest_framework import routers from core.viewsets import UserViewSet from django.urls import path, include # Routers provide an easy way of automatically determining the URL conf. router = routers.DefaultRouter() router.register(r'users', UserViewSet) # Wire up our API using automatic URL routing. # Additionally, we include login URLs for the browsable API. urlpatterns = [ path('', include(router.urls)) ]auth_userを作る
写真
おそらくpythonを実行すると上のようなエラーが出てくると思う。
これはテーブルがないことによるエラーなので
migrate
することで解決できる。python manage.py makemigrations python manage.py migratesuperuserを作る
Django の管理画面を利用するためには基本的にsuperuserを作ってアカウント登録する必要があります。python manage.py createsuperuserするとこんなコマンドが出てくるので情報を打ち込んでいきましょう。
$ python manage.py createsuperuser Username (leave blank to use 'user1'): admin Email address: admin@keicode.com Password: # パスワードを入力 Password (again): This password is too common. # パスワードが単純過ぎる場合はエラー発生 Password: Password (again): Superuser created successfully.新しいモデルの作り方
『model.py』の中身に使用するモデルクラスの定義していく。
モデルクラスはDjangoフレームワークが提供する『Django.db.models.Model』を親クラスとして継承して作成します。
モデルクラス作成の基本的なコードは以下のとおりです。
models.py#モデルクラスの作成 from django.db import models class モデル名(models.Model): フィールド名 = フィールドクラス(・・・,フィールドオプションの指定,・・・)ここでは、『Account』というモデルクラスを定義して、その中のフィールドオブジェクトとして[fb_token][ig_token]を作成しています。そして、userモデルに紐付けます。
models.pyfrom django.db import models from django.contrib.auth.models import User class Account(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) fb_token = models.CharField(max_length=1000) ig_token = models.CharField(max_length=1000) def __str__(self): return str(self.id)OneToOneField/ 1対1(1つのユーザーは1つのアカウントしかもてない)
on_delete=models.CASCADE/ 外部キーで参照してるオブジェクトが削除されたとき、その削除に合わせて行われる処理
models.CharField(max_length=1000)/ 文字列のフィールを作るモデルをdjangoapiのadminに反映させる
admin.py
にアカウントモデルを登録することによりAPI上でアカウントモデルを確認することができる。admin.pyadmin.site.register(Account)Api rootに作ったモデル情報を反映させる
先程作った
serializers.py
、viewsets.py
にそれぞれのモデルに対応するコードを書きApi Rootでアカウントの情報を確認できるようにする。serializerの機能について学びたい人はこちらを確認してください↓↓
[Django REST Framework] Serializer の 使い方 をまとめてみた
ここでは
AccountSerializer
を作っていくserializers.pyfrom rest_framework import serializers from core.models import Account class AccountSerializers(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'user', fb_token', 'ig_token']次にAccountViewSetクラスを作る。
viewsets.pyclass AccountViewSet(viewsets.ModelViewSet): queryset = Account.objects.all() serializer_class = AccountSerializerAccountViewSetクラスト作れたらそれをurls.pyで使う
urls.pyfrom django.contrib import admin from rest_framework import routers + from core.viewsets import UserViewSet, AccountViewSet from django.urls import path, include router = routers.DefaultRouter() router.register(r'users', UserViewSet) + router.register(r'accounts', AccountViewSet)すると、こうなる
最後に
viewsets.py
にpermission
クラスを設定しよう。viewsets.pyclass AccountViewSet(viewsets.ModelViewSet): queryset = Account.objects.all() serializer_class = AccountSerializer + # permission_classes = [permissions.IsAuthenticated] + permissions_classes = [AllowAny]
[AllowAny]
では誰でも編集することができるが、[permissions.IsAuthenticated]
では権限の持った人しかmodelの値を編集することができない.今日の課題
`axiosを使ってフロントエンドから取得したクエリパラメーターをdjangoのapi(fb_token, ig_tokenフィールド)に入れる。
- 投稿日:2021-03-01T00:56:48+09:00
Vue.jsでページネーションを実装
Rails + Vue.jsを使用しています
Vue.js初心者なので分かりにくい説明だと思いますがよろしくお願いします
前提条件
APIを使用してJSONでデータを返している前提で書いています
分からない方は以下などを参考にすれば分かると思います
既存のRailsアプリにJSONを返すAPIを実装してみる
Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門実装
vuejs-paginateを使って実装します
準備としてmain.jsに以下を記述main.js
import Paginate from 'vuejs-paginate' Vue.component('paginate', Paginate)まずは全体のコード
完成コード(TweetsPage.vue)
<template> <div class="tweets"> <div v-for="e in getLists" :key="e.id"> {{e.id}} {{e.name}} </div> <paginate :v-model="currentPage" :page-count="getPageCount" :click-handler="clickCallback" :page-range="3" :margin-pages="2" :prev-text="'<'" :next-text="'>'" :container-class="'pagination'" :page-link-class="'page-link'"> </paginate> </div> </template> <script> import axios from 'axios' export default { data() { return { tweets: [], currentPage: 1, parPage: 10, } }, mounted() { this.fetchTweets() //fetchTweetsを呼ぶ }, methods: { fetchTweets() { axios .get(`/api/v1/tweets/tweets.json`) .then(response =>{ this.tweets = response.data; }) }, clickCallback: function (pageNum) { this.currentPage = Number(pageNum); }, }, computed: { getLists: function() { let current = this.currentPage * this.parPage; let start = current - this.parPage; return this.tweets.slice(start, current); }, getPageCount: function() { return Math.ceil(this.tweets.length / this.parPage); } } } </script>順番に簡単に解説していきます
まずはdetaの準備
import axios from 'axios' export default { data() { return { tweets: [], //axiosで取ってきたデータを格納するため currentPage: 1, //現在いるページ parPage: 10, //1ページで表示するデータ数 今回は1ページにつき10個のデータを表示 } } mounted() { this.fetchTweets() },axiosというのを使ってJSONで返ってきているデータを取得してtweetsに格納
methods: { fetchTweets() { axios .get(`/api/v1/tweets/index.json`) //json形式のデータが確認できるURLを記述 .then(response =>{ this.tweets = response.data; //dataで定義したtweetsに取ってきたデータを格納 }) },出力したいデータを出力
そしてページネーション実装<template> <div v-for="e in getLists" :key="e.id"> //Railsでいう each doのようなものでしょうか 繰り返しでgetList(この後出てくる)の返り値であるデータを全て表示 {{e.id}} {{e.name}} </div> <paginate :v-model="currentPage" // 現在のページ :page-count="getPageCount" //総ページ数 :click-handler="clickCallback" //クリック(ページ移動)する度にclickCallbackを呼び出す :page-range="3" //3ページ以降は[...]で省力する :margin-pages="2" //ラスト2ページから省力しない :prev-text="'<'" //戻るボタンは[<] :next-text="'>'" //進むボタンは[>] :container-class="'pagination'" :page-link-class="'page-link'"> </paginate> </template>ページネーションの処理
現在のページを決めたり、今いるページに合ったデータだけを取得したり、全部で何ページ必要か計算したり
//現在のページを決める処理 clickCallback: function (pageNum) { this.currentPage = Number(pageNum); //ページネーションで選択したページを現在のページにする 2ページを選択したらcurrentPageに2が代入される 3ページなら3 }, }, computed: { //必要なデータだけを取得する処理 getLists: function() { let current = this.currentPage * this.parPage; //現在のページ×1ページに表示する数 let start = current - this.parPage; return this.tweets.slice(start, current); //そのページに合ったデータだけを表示 1ページ目ならtweetsの0〜9番目を、2ページ目なら10〜19番目のデータを表示 }, //総ページ数を決める処理 getPageCount: function() { return Math.ceil(this.tweet.length / this.parPage); //全部で何ページ必要か } }後はapplication.html.erbなどにBootstrapのスタイルを適用するCDNを呼び出せば見た目が整います
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.css">おかしな箇所があればコメントください!
最後までご高覧いただきましてありがとうございました!参考記事
- 投稿日:2021-03-01T00:05:36+09:00
express+vueで動画収録アプリを作ってみた
はじめに
PC1台で動画収録と簡易編集を行えるアプリケーションを作成した話。
https://github.com/tatsuya-nagashima/vue-electron-video-recorder.git主な機能
- 動画の収録
- 外部入力の動画を収録しつつ、その様子をプレイヤーで表示する
- 動画のファイル切り出し
- 指定した範囲を切り出してファイル保存することができる
- 動画のチャプター登録
- 指定した範囲をチャプターとして登録しておき、後から見直すことができる
- DVR再生
- 収録しながら過去の一部分のみを再生することができる
- その他
- プレイヤーの再生/停止、シーク, IN点/OUT点の指定をショートカットキーで行える
- スクラビング(プレイヤーの映像をシークに追従させる)が行える
などデモ
構成
サーバサイド: express + sqlite + ffmpeg
フロント: vue + vuetify + hls.jsUI操作からのリクエストを受け付けるアプリケーションサーバとしてexpressを利用している。
動画情報の管理はsqliteで行なっており、動画の収録や切り出しにはffmpegを用いている。