20200628のvue.jsに関する記事は6件です。

【Vue Rails】Vue + Railsで"Hello Vue!"表示 

Vue + Railsアプリ作成

◆ Railsアプリ作成

// "-webpack=vue"オプションでVue.js使用可能
$ rails new <アプリケーション名> -webpack=vue

◆ model作成

// カラム名:name データ型:text
$ rails g model sample name:text

◆ migrationファイル編集(Hello.Vue!表示には不要)

db/migrate/20200627045139_create_sample.rb
class CreateSample < ActiveRecord::Migration[6.0]
  def change
    create_table :sample do |t|
      t.text :name, null: false, default: ""
    end
  end
end

◆ マイグレーション

$ rails db:create      //データベース作成
$ rails db:migrate    //マイグレーション実施

◆ controller作成

app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
  end
end

◆ routes.rb編集

config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end

◆ index.html.erb編集

app/views/home/index.html.erb
<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>

◆ hello.vue.js(デフォルトで設定済)

app/javascript/packs/hello_vue.js
import Vue from 'vue'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const el = document.body.appendChild(document.createElement('hello'))
  const app = new Vue({
    el,
    render: h => h(App)
  })

  console.log(app)
})

◆ app.vue(デフォルトで設定済)

app/javascript/app.vue
<template>
  <div id="app">
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!"
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>

備忘録

◆ before_action

  • メソッドを定義して、before_actionにセットする
login_controller.rb
class LoginController < ApplicationController
  before_action :set_answer

  def set_answer
    @sample = "Hello World!"  
  end
end

◆ rescue_from

  • 例外処理。エラー処理を行う画面を設定する
  • app/controller/application_controller.rbに記述する
app/controller/application_controller.rb
class ApplicationController < ActionController::Base

  rescue_from ActiveRecord::RecordNotFound, with: :rescue404

end

遭遇したエラー

◆ エラー内容①

Webpacker::Manifest::MissingEntryError in Home#index

解決策:Webpackインストール

$ yarn
$ bin/yarn
$ webpack
$ webpack

◆ エラー内容②

Error: vue-loader requires @vue/compiler-sfc to be present in the dependency tree.

解決策:vue-loaderダウングレード

$ npm remove vue-loader
$ npm install --save vue-loader@15.9.2
$ yarn add vue-loader@15.9.2

◆ エラー内容③

Sprockets::Rails::Helper::AssetNotFound in Home#index
 <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

解決策:app/views/layouts/application.html.erb編集

app/views/layouts/application.html.erb
<!-- javascript_include_tagの行を削除 -->
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

参考文献

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

【Vue.js】Scoped CSSのscoped具合を検証してみた

Vue.jsのScoped CSSは完全にはscopedじゃない、という話を聞いたので検証してみました。
結果、コンポーネント最上位の要素と、slotについては気をつける必要があることが分かりました。

参考記事

親コンポーネントのstyleが子コンポーネントに影響を与える仕組みは、以下が詳しいです。

検証環境

  • OS: macOS Catalina 10.15.5
  • ブラウザ: Google Chrome 83.0.4103.116(Official Build)(64bit)
  • Vue.js: 2.6.11


検証1: 素朴にstyleを当てた場合

親、子、孫コンポーネントにそれぞれ違った色を割り当てました。
すると、各コンポーネントの最上位の要素には親コンポーネントのスタイルが適用されてしまいました。
1.png

Parent.vue
<template>
  <div class="root-div">
    this is root div of parent
    <h1 class="my-title">this is h1 of parent</h1>
    <div  class="h2-container">
      <h2>this is h2 of parent</h2>
    </div>
    <Child />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Child from "@/components/Child.vue";

export default Vue.extend({
  name: "Parent",
  components: {
    Child,
  },
});
</script>

<style scoped lang="scss">
.root-div {
  color: red;
}
.my-title {
  color: red;
}
h2 {
  color: red;
}
</style>
Child.vue
<template>
  <div class="root-div">
    this is root div of child
    <h1 class="my-title">this is h1 of child</h1>
    <div  class="h2-container">
      <h2>this is h2 of child</h2>
    </div>
    <GrandChild />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import GrandChild from "@/components/GrandChild.vue";

export default Vue.extend({
  name: "Child",
  components: {
    GrandChild,
  },
});
</script>

<style scoped lang="scss">
.root-div {
  color: blue; // こいつが効いていない
}
.my-title {
  color: blue;
}
h2 {
  color: blue;
}
</style>
GrandChild.vue
<template>
  <div class="root-div">
    this is root div of grandchild
    <h1 class="my-title">this is h1 of grandchild</h1>
    <div  class="h2-container">
      <h2>this is h2 of grandchild</h2>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from "vue";

export default Vue.extend({
  name: "GrandChild",
});
</script>

<style scoped lang="scss">
.root-div {
  color: green;
}
.my-title {
  color: green;
}
h2 {
  color: green;
}
</style>


検証2: 全称セレクタ(*)を使った場合

*を使って乱暴にstyleを指定した場合どうなるかを見てみました。
結果、検証1と同じく、各コンポーネント最上位の要素だけは親コンポーネントのstyleの影響が出ました。
※検証1のコードから、Child.vueだけ変更しました。
1.png

Child.vue
<template>
  <div class="root-div">
    this is root div of child
    <h1 class="my-title">this is h1 of child</h1>
    <div  class="h2-container">
      <h2>this is h2 of child</h2>
    </div>
    <GrandChild />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import GrandChild from "@/components/GrandChild.vue";

export default Vue.extend({
  name: "Child",
  components: {
    GrandChild,
  },
});
</script>

<style scoped lang="scss">
.root-div * {
  color: blue;
}
* {
  color: blue;
}
* * {
  color: blue;
}
</style>


検証3: globalのcssがある場合

当たり前ですが、ページ全体に適用されているcssがある場合、競合します。
例えば、ページ全体に* { color: black!important }を当てたら、すべて黒になります。
1.png

App.vue
<style lang="scss">
* {
  color: black!important; // プロダクトコードで書いたら殴られるやつ
}
</style>



もちろん、!importantを付けなければ、コンポーネント内のcssが優先的に適用されます。
(この辺はScoped CSSというよりはCSSそのものの話)
1.png

App.vue
<style lang="scss">
* {
  color: black;
}
</style>


検証4: slotを使った場合

slotを使って、親から子へタグを渡した場合、渡したタグには親コンポーネントのstyleが適用されました。
1.png

Parent.vue
<template>
  <div class="root-div">
    this is root div of parent
    <h1 class="my-title">this is h1 of parent</h1>
    <div  class="h2-container">
      <h2>this is h2 of parent</h2>
    </div>
    <Child>
      <!-- 親からタグごとslotを挟むと、親のstyleが適用される -->
      <template #my-slot>
        <p>slot: this is p of parent</p>
        <div>
          <h2>slot: this is h2 of parent</h2>
        </div>
      </template>
    </Child>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Child from "@/components/Child.vue";

export default Vue.extend({
  name: "Parent",
  components: {
    Child,
  },
});
</script>

<style scoped lang="scss">
.root-div {
  color: red;
}
.my-title {
  color: red;
}
h2 {
  color: red;
}
p {
  color: red;
}
</style>
Child.vue
<template>
  <div class="root-div">
    this is root div of child
    <h1 class="my-title">this is h1 of child</h1>
    <div  class="h2-container">
      <h2>this is h2 of child</h2>
    </div>
    <slot name="my-slot">
        <p>slot: this is p of child</p>
        <div>
          <h2>slot: this is h2 of child</h2>
        </div>
    </slot>
    <GrandChild />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import GrandChild from "@/components/GrandChild.vue";

export default Vue.extend({
  name: "Child",
  components: {
    GrandChild,
  },
});
</script>

<style scoped lang="scss">
.root-div {
  color: blue;
}
.my-title {
  color: blue;
}
h2 {
  color: blue;
}
p {
  color: blue;
}
</style>



一方、親から子へ文字列だけを渡した場合、子のstyleが適用されました。
1.png

Parent.vue
<template>
  <div class="root-div">
    this is root div of parent
    <h1 class="my-title">this is h1 of parent</h1>
    <div  class="h2-container">
      <h2>this is h2 of parent</h2>
    </div>
    <Child>
      <!-- 親から文字列だけを渡すようにすれば、親のstyleは適用されない -->
      <template #my-slot-p>slot: this is p of parent</template>
      <template #my-slot-h2>slot: this is h2 of parent</template>
    </Child>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Child from "@/components/Child.vue";

export default Vue.extend({
  name: "Parent",
  components: {
    Child,
  },
});
</script>

<style scoped lang="scss">
.root-div {
  color: red;
}
.my-title {
  color: red;
}
h2 {
  color: red;
}
p {
  color: red;
}
</style>
Child.vue
<template>
  <div class="root-div">
    this is root div of child
    <h1 class="my-title">this is h1 of child</h1>
    <div  class="h2-container">
      <h2>this is h2 of child</h2>
    </div>
    <p><slot name="my-slot-p">slot: this is p of child</slot></p>
    <div>
      <h2><slot name="my-slot-h2">slot: this is h2 of child</slot></h2>
    </div>
    <GrandChild />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import GrandChild from "@/components/GrandChild.vue";

export default Vue.extend({
  name: "Child",
  components: {
    GrandChild,
  },
});
</script>

<style scoped lang="scss">
.root-div {
  color: blue;
}
.my-title {
  color: blue;
}
h2 {
  color: blue;
}
p {
  color: blue;
}
</style>


で、結局何に気をつければいいのか

  • コンポーネント最上位の要素になるべくstyleを当てない
  • 当てざるを得ない場合、.component-name-root { display: flex }のように、重複しないクラス名を付けて、styleを指定する
  • 自前でslotを作る場合、極力DOM構造は子コンポーネント側で定義する
  • デザインフレームワーク(vuetifyとか)の制約上slotにDOMを渡さざるを得ない場合は、予期せぬstyleが適用されないよう気をつける

所感

完全でないとはいえ、知らずに使っていてもそんなに気にならない程度にはscopedにできていると感じました。
個人的にはslotを使わないため、各コンポーネントの最上位のクラス名だけ気をつければ問題なし! という印象です。
Scoped CSS便利。

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

Rails+vue+Parcel環境でSFCのスタイルが効かなかった件

単一コンポーネントで定義したスタイルが反映されない件

Rails+vue+Parcel環境で開発をやっていた時vueのSFCで書いたスタイルが適用されない
いろいろ調べても記事はあまりなかった。
コードをしっかり確認したら解決したのでまとめてみました。

解決法

CSSを読み込むヘルパーメソッドを自作する

app/helpers/application_helper.rb
module ApplicationHelper
    ・・・

    def javascript_pack_tag(name)
        javascript_include_tag(manifest["#{name}.js"])
    end

+   def stylesheet_pack_tag(name)
+       stylesheet_link_tag(manifest["#{name}.vue"])
+   end

    ・・・

あとは読み込みたいスタイルがあるvueファイルを下記のように指定するだけ。

app/views/static_pages/home.html.erb
<% if logged_in? %>
・・・

      <div id="app"></div>
      <%= javascript_pack_tag 'index' %>
      <%= stylesheet_pack_tag '読み込みたいSFCの名前' %>

・・・

なぜこれで解決するの?

npm run watchでやっている内容は以下の通り
parcel watch app/javascripts/packs/index.html -d public/packs --public-url /packs/ --hmr-port 50000
トランスパイルしたものはpublic/packsに入ってくる。
ここで作成されるmanifestファイルの内容は以下の通り。


{
  "index.html": "/packs/index.html",
  "index.js": "/packs/packs.e31bb0bc.js",
  "FeedList.vue": "/packs/packs.e31bb0bc.css",
  "FeedItem.vue": "/packs/packs.e31bb0bc.css"
}

この内容をさっきのヘルパーでは読み込んでいる。

app/helpers/application_helper.rb
module ApplicationHelper
・・・

  private

    def manifest
      @manifest ||= load
    end

    def load
      manifest_path = Rails.root.join('public', 'packs', 'parcel-manifest.json')
      if manifest_path.exist?
        JSON.parse manifest_path.read
      else
        {}
      end
    end
end

これでマニフェストに書かれていることが読み込まれるので、先ほど作ったヘルパーメソッド(stylesheet_pack_tag)内でstylesheet_link_tagを使うことでrailsにCSSを読み込む!

後書き

ドキュメントに沿ってコピペだけしてた部分でこうした問題があったので、しっかりコードをよもうと思いました。

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

File , Blob で、ファイルのエクスポート/ インポート機能とIndexedDB登録, Vue CLI版

概要

前と同様、IndexedDB + Vue CLIで
Dexie.js ライブラリを使用した構成となり。
json ファイルのエクポート、インポートの調査してみました
File API , Blob等で実現できそうでした。

・インポートした jsonファイルを IndexedDB
 登録まで。可能でした

構成

Chrome 83
Vue CLI
dexie : 3.0.1
vue: 2.6.11
vue-router

参考

File
https://developer.mozilla.org/ja/docs/Web/API/File

Blob:
https://developer.mozilla.org/ja/docs/Web/API/Blob

http://www.tohoho-web.com/html5/file_api.html

https://qiita.com/wadahiro/items/eb50ac6bbe2e18cf8813

package.json

https://github.com/kuc-arc-f/vue_spa3b_3files/blob/master/package.json


Vue components

・json生成、エクスポート
test.vue
https://github.com/kuc-arc-f/vue_spa3b_3files/blob/master/src/components/Files/test.vue

var arr = [
    {id: 1  , name: "n1"},
    {id: 2  , name: "n2"},
    {id: 3  , name: "n3"},
    {id: 4  , name: "n4"},
    {id: 5  , name: "n5"},
];
var content = JSON.stringify( arr );
var blob = new Blob([ content ], { "type" : "application/json" });

・jsonアップロード, db登録
test2.vue
https://github.com/kuc-arc-f/vue_spa3b_3files/blob/master/src/components/Files/test2.vue

change_proc: function(){
    console.log("#-change_proc")
    var self = this
    var files = window.document.getElementById('file1').files;
    for (var i = 0; i < files.length; i++) {
        var file = files[i];
        console.log("i: " + i );                
        console.log("Name: " + file.name);
        console.log("Size: " + file.size);
        console.log("Type: " + file.type);
        console.log("Date: " + file.lastModified);
        console.log("Date: " + file.lastModifiedDate);
        var reader = new FileReader();
        reader.onload = function(evt) {
            console.log("State: " + evt.target.readyState);
            console.log("Result: " + evt.target.result);
            var result =evt.target.result;
            var dat = JSON.parse(result || '[]')
            self.add_item(dat)
            self.items = dat
            console.log(dat)
        //document.getElementById("output1").innerHTML = evt.target.result;
        };
        reader.onerror = function(evt) {
            console.log(evt.target.error.name);
        };
        reader.readAsText(file, "utf-8");             
    }            
},


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

Vueを複数人で開発する環境を試してみた

背景

Vue開発してると、色々ライブラリインストールとかが発生する。そんな事をしていると、複数人で開発していると、人によってインストールタイミングが違うので、結果モジュールのバージョン違ったりして将来的なトラブルの種になりそうと感じていた。なにより、production環境と開発環境が違ってくる状況になるのが一番まずい。
調べていると、Qiitaに良記事が色々あり、その問題を解消できそうだったので実際に試してみた。

実現したい事

  • ソースコード管理はgit
  • gitに存在する設定ファイルなどの情報で、複数人が同構成環境でVueの開発が出来るように
  • モジュールの変更も簡単に複数人の環境へ再現したい
  • 各種モジュールのバージョンは全指定(後にインストールした人とのバージョンが違うとか無い様に)
  • ホスト側で行ったソース編集をすぐに反映したい(開発モード使用したい)

ベースとなるのはこちらの記事。Dockerはこの手の環境に関する検討を1から簡単にやり直せるので、本当にすごく良いです。※最初は別記事参考にしたりしたので、細かい所で違う部分あります。
ローカルを汚さずdockerを使ってvue.jsの開発環境を作る[vuecli4]

前準備

docker/docker-compose インストール

さすがにdockerはホスト側にインストールしなければいけないので、以下サイトを参考にインストール
Ubuntu 18.04にDockerをインストールする(+docker-composeも)
もちろん、OSがWinでもMacでもDockerは使えるので、開発者のOSが違っても対応できるのもDockerの良い点ですね。

gitリポジトリ準備

  • githubでテスト用プロジェクト作成(vueprj-test01)
  • ホストでクローン(git clone https://github.com/silverbox/vueprj-test01.git)
  • developブランチ準備(vueprj-test01 に移動して、 git checkout -b develop origin/master

初期構築

docker-compose.yml, Dockerfile 準備

  • ホスト側のgitリポジトリフォルダ(vueprj-test01)以下に app フォルダを準備
  • コンテナ側は /app 以下に実プロジェクト作成
  • nodejs用のDockerイメージは(公式サイト)、現時点でのLTSの最新版っぽい12.18.1を使う
  • vue/cliとvue/cli-initは公式サイトで、現時点でのリリース最新版っぽい4.4.1を使う
vueprj-test01/docker-compose-vueini.yml
version: '3.7'
services:
  frontvue:
    build:
      context: .
      dockerfile: Dockerfile-vue
    ports:
      - 8080:8080
    volumes:
      - ./context:/app
      - /app/node_modules
    container_name: vueprj-test01
    tty: true
Dockerfile-vue
FROM node:12.18.1-alpine

WORKDIR /app

RUN apk update
RUN npm install -g @vue/cli@4.4.1
RUN npm install -g @vue/cli-init@4.4.1

ビルドして起動

vueprj-test01配下
sudo docker-compose -f docker-compose-vueini.yml build
sudo docker-compose -f docker-compose-vueini.yml up
Creating network "vueprj-test01_default" with the default driver
Creating vueprj-test01 ... done
Attaching to vueprj-test01

起動状態になった。

Vueプロジェクト作成

コンテナにログイン

bashは使えなかったのでshを使用。
docker exec -it vueprj-test01 sh

バージョン確認。指定はちゃんと反映されてる。

コンテナ内
/app # vue --version
@vue/cli 4.4.1
/app # node -v
v12.18.1

vueプロジェクト作成(選択肢はパッケージにnpm選択した事以外はデフォルトを選択)

コンテナ内
/app # vue create .
コンテナ内で開発モードで実行。
/app # npm run serve
ホスト側vueprj-test01配下。変更できるように権限変更
sudo chown -R ubuntu:ubuntu .

この状態でホスト側コードエディタで、vueprj-test01/app/src/App.vue<HelloWorld msg="Welcome to Your Vue.js App"/> 部分の文言を変更して自動的に更新される事確認。

gitにpush

既に.gitignoreが作成されているので、node_modulesとか除外されてる。
git add .
git commit -m "base project"
[develop 4ce861d] base project
 13 files changed, 11687 insertions(+)
 create mode 100755 Dockerfile-vue
 create mode 100644 app/.gitignore
 create mode 100644 app/README.md
 create mode 100644 app/babel.config.js
 create mode 100644 app/package-lock.json
 create mode 100644 app/package.json
 create mode 100644 app/public/favicon.ico
 create mode 100644 app/public/index.html
 create mode 100644 app/src/App.vue
 create mode 100644 app/src/assets/logo.png
 create mode 100644 app/src/components/HelloWorld.vue
 create mode 100644 app/src/main.js
 create mode 100755 docker-compose-vueini.yml

別の開発者を想定して環境構築

このgitリポジトリを元に別フォルダにcloneして、構築を行う。
本来は別サーバーでやりたいところだけど、dockerなのでコンテナを一回削除すればほぼ別サーバーと同じ条件になるのでそれで実験。

一応再ビルドして、Dockerコンテナ起動。

コンテナ削除して、新フォルダ作成。そしてそのフォルダ以下で構築。

~/vueprjtest/vueprj-test01$ sudo docker-compose -f docker-compose-vueini.yml rm
~/vueprjtest/vueprj-test01$ mkdir ~/vueprjtest2
~/vueprjtest/vueprj-test01$ cd ~/vueprjtest2
~/vueprjtest2/vueprj-test01$ git clone https://github.com/silverbox/vueprj-test01.git
~/vueprjtest2/vueprj-test01$ cd vueprj-test01
~/vueprjtest2/vueprj-test01$ sudo docker-compose -f docker-compose-vueini.yml build
~/vueprjtest2/vueprj-test01$ sudo docker-compose -f docker-compose-vueini.yml up

再度コンテナ内に入る。この状態では、コンテナに標準にインストールされている部分以外は無い状態。ただ、gitにはpackage.json,package-lock.jsonが上がっているので、コンテナ内から見える状態になっている。npm install でそれを反映。そして開発モードで実行。

コンテナ内
npm install
npm run serve

同様に、ホスト側の新フォルダ配下、vueprj-test01/app/src/App.vue<HelloWorld msg="Welcome to Your Vue.js App Test"/> 部分の文言を変更して自動的に更新される事確認。

ライブラリ追加

別開発者がライブラリを追加した事想定。ついでに、先は手動で行った処理を加える(本来は最初のgit push時に反映しておくべき)。

Dockerfile-vue:element-uiとaxios追加
FROM node:12.18.1-alpine

WORKDIR /app

COPY app/package.json .
COPY app/package-lock.json .

RUN apk update
RUN npm install -g @vue/cli@4.4.1
RUN npm install -g @vue/cli-init@4.4.1
RUN npm install
RUN npm install --save element-ui@2.13.2
RUN npm install --save axios@0.19.2
main.jsでaxiosを宣言して代入してみる。
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'

Vue.config.productionTip = false

Vue.prototype.$axios = axios;

new Vue({
  render: h => h(App),
}).$mount('#app')
再ビルド
sudo docker-compose -f docker-compose-vueini.yml rm
sudo docker-compose -f docker-compose-vueini.yml build
sudo docker-compose -f docker-compose-vueini.yml up

そして、http://localhost:8080 でページが動く事確認。

結論

  • .gitignoreとかはちゃんとvue createで作ってくれる。
  • ライブラリ管理もpackage.json,package-lock.jsonで管理されて、それがnpm installで再現される。
  • なのでpackage.jsonが作られるまでの準備のDockerfileと、それ以後のDockerfileは分ける。
  • ライブラリ変わったら別開発者はコンテナ再作成か、コンテナ内でnpm installすればよさそう。

はまったポイント

最初、vue init webpack . でvueプロジェクト作成をしていた。
しかし、http://localhost:8080/ でアクセス出来る事を確認する時にどうもうまく行かない。そんな事を色々調べていたら、以下の神ページを発見。
vue-cli のテンプレートを Docker で動かす時の注意
config/index.js を変えなくてはいけない、というか、vue init webpack . は古い形式らしい事も知る。
書かれている通り、localhost部分を0.0.0.0にしたらホストからアクセスできるようになった。

動作したとはいえ、きれいな環境を目指しているのでvueプロジェクト作成やり直し。

ホスト側vueprj-test01配下。Ctrl+Cでdocker-composeを止める。
sudo docker-compose -f docker-compose-vueini.yml rm
rm -r app
mkdir app
sudo docker-compose -f docker-compose-vueini.yml up

環境構築も簡単にやり直せるのがDockerの良い所ですね。

ちなみにこの変更で開発モード実行コマンドも npm run dev から npm run serve 変わったらしい。configがdevとproで分かれたりもしてない?取り急ぎ今回は、目的とは違う部分なので気にしない事に。

参考にさせて頂いたサイト

Ubuntu 18.04にDockerをインストールする(+docker-composeも)
ローカルを汚さずdockerを使ってvue.jsの開発環境を作る[vuecli4]
Vue.jsの開発環境をDockerで構築する手順
vue-cli バージョン指定してインストールする
vue-cli のテンプレートを Docker で動かす時の注意

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

【Vue】オブジェクトを変更したい時どうするか?

Vueのオブジェクトの変更方法をまとめ

Vueのdata()にあるオブジェクトについての話。

取得は通常のJSのオブジェクトの操作と同様にキーを使えば問題なかったが、
追加と削除で嵌ったので備忘録として残しておく。

以下、参考にしたページ

次のようなVueインスタンスのdata()charObjという空のオブジェクトがセットしてあるとする。

export default {
  data () {
    return {
      charaObj: {}
    }
  }
}

プロパティを追加する

プロパティを追加したい時、通常のJSのオブジェクト同様obj.anyKey = anyValとやってしまいたくなるがこれだとリアクティブにデータが反映されない(=データ更新してもテンプレート(画面)上に反映されない)ので、ダメということらしい。

// リアクティブにデータが反映されないのでこの書き方はダメ
this.charaObj.hero = '範馬刃牙'

プロパティを追加したい時は$setを使う。
慣れない書き方だが、これでリアクティブにプロパティを追加できる。
第1引数にオブジェクトを、第2引数にキー、第3引数に値を渡す。

// リアクティブになるやつ
this.$set(this.charaObj, 'hero', '範馬刃牙')

プロパティをまとめて追加したい

スプレッド演算子...を使って追加したいプロパティを含むオブジェクト内で展開すればいい。

this.charObj = {...this.charObj, parent: '範馬勇次郎', friend: '烈海王'}

またはObject.assign()を使って新しいオブジェクトを作って代入する方法でもできるらしい。

this.charaObj = Object.assign({}, this.charaObj, {parent: '範馬勇次郎', friend: '烈海王'})

プロパティを削除する

追加の時と同じで、いつも通りに削除しようとするとリアクティブにならない。

// リアクティブにデータが反映されないのでこの書き方はダメ
delete this.charaObj.hero

プロパティを削除したい時は$deleteを使う。第1引数に対象のオブジェクトを、第2引数に削除したいプロパティのキーを渡す。

// リアクティブになるやつ
this.$delete(this.charaObj, 'hero')

全削除したい

最初、空のオブジェクトを再代入で初期化できないかと考えたが、うまくいかなかった。

// 再代入はうまくいかない
this.obj = {}

この場合は、キーの配列をObject.keys()で取得してループでdeleteを使って削除したところうまくいった。

// プロパティを全削除 
Object.keys(this.charObj).forEach(key => {
    this.$delete(this.charObj, key)
})

リアクティブにVueインスタンスのデータを削除するには先に書いた$deleteを使う。

プロパティを全て入れ替えたい

オブジェクトを一度空にしてからまとめて追加すればよい

オブジェクト自体を削除したい

あまり使うケースは無さそうだが、プロパティではなくオブジェクト自体(Vueインスタンスのトップレベルのプロパティ)を削除したい場合はどうするか?

$deleteを使いたくなるところだが、トップレベルのを削除する時は
$deleteを使おうとすると警告が出るので使っちゃダメっぽい。

// トップレベルのプロパティを削除しようとエラーが出る
this.$delete(this, 'charObj')

この場合はnullを入れればよいみたい。

// charObjを削除する
this.charObj = null
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む