2019年6月16日 星期日

[Vue.js] v-for設定key的作用與影響


v-for迭代陣列或物件時需要設定key,是為了避免重複產生DOM元素而浪費資源,因此將key視為一個辨識的依據,所有的key必須保持唯一。因此如果key值不小心重複,console甚至會出現Duplicate keys detected: ... This may cause an update error. 這樣的警示訊息。

為了顯示key的作用和影響,用下面的例子來看,程式內容大意是根據menu的內容產生多個product-box,兩個唯一的差別是前著用indexkey,後者則是用id當作key,此外多加一個button來更動資料的內容。
<template>
  <div>
    <product-box v-for="item,index in menu" :key="index" :value="item.id">
      {{ item.name }}
    </product-box>

    <product-box v-for="item in menu" :key="item.id" :value="item.id">
      {{ item.name }}
    </product-box>

    <button @click="addFirstElement">Add</button>
  </div>
</template>

<script>
import ProductBox from './ProductBox'
export default {
  data () {
    return {
      menu: [
        {id: 'A001', name: 'milk tea'},
        {id: 'A002', name: 'juice'}
      ]
    }
  },
  methods: {
    addFirstElement: function() {
      let first_elm = [{id: 'A000', name: 'coffee'}];
      this.menu = first_elm.concat(this.menu);
    }
  },
  components: {
    ProductBox
  }
}
</script>

ProductBox.vue
<template>
  <div>
    {{ dispay_text }} <slot></slot>
  </div>
</template>

<script>
  
  export default {
    data: function() {
      return {
        dispay_text: ''
      }
    },
    props: {
      'value': String
    },
    created: function() {
      this.dispay_text = this.value;
    }
  }
</script>

初始的情況下:
A001 milk tea
A002 juice

接著,點button在開頭插入一個新的資料,預想的顯示如下,如果用id當作key的話也是產生一樣的結果。
// key=id

A000 coffee
A001 milk tea
A002 juice

這時因為用index當作key,所以原本index 1和2因為沒有偵測到變化並不會重新產生,也就是不會重新經歷created,所以出現所謂的update error,結果會變成:
// key=index

A001 coffee
A002 milk tea
A002 juice

雖然用index當作key很方便,但並非所有的情況都適合使用index當作key。

2019年6月10日 星期一

[Vue.js] 共用Domain Name 部屬多個vue專案


接續『[Vue.js] vue-router設定history mode移除網址的#』的內容,可以在web server裡部屬vue的專案,如果要共用同一個domain name,用不同的子目錄(subdirectory)來區分時,只要根據下面的步驟稍微調整你的專案,既不會影響原本的開發模式,也能在正式區讓多個專案同時運行。

假設兩個專案project-Aproject-B分別為:
1. project-A: /var/www/project_a
http://my.project
2. project-B: /var/www/project_b
http://my.project/group/

所有project-B的URL,都會多一個 /group/ 的子目錄;反之,帶有 /group/ 的網址也會自動與project-B的路由進行比對。
project-A的設定方式不再說明,可以參考『[Vue.js] vue-router設定history mode移除網址的#』,下面講解project-B的設定方式。

Step1. vue-router
設定base
// src/router/index.js
 export default new Router({
   base: '/group/',
   mode: 'history',
   ...
 }

Step2. build參數
設定assetsPublicPath,請注意有兩個不同的key,須設定的是buildassetsPublicPath
// config/index.js
 module.exports = {
   dev: {
       ...
   },
   build: {
     assetsPublicPath: '/group',
     ...
   }
 }

Step3. build
npm run build
取得目錄dist/底下的檔案,搬到目的的資料夾/var/www/project_b

Step4. 建立.htaccess
將檔案放到/var/www/project_b,也就是project-B相同的目錄。
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . group/index.html [L]
</IfModule>

Step5. Apache Config
將檔案放到/var/www/html/project_b,也就是project-B相同的目錄。
<VirtualHost *:443>
  ServerName my.project
  DocumentRoot /var/www/project_a
  DirectoryIndex index.html
  <Directory /var/www//project_a>
    AllowOverride all
  </Directory>
  
  Alias /group /var/www/project_b
  <Directory /var/www/project_b>
    AllowOverride All
  </Directory>
</VirtualHost>

sudo systemctl restart apache2
請記得重啟apache2,設定就完成囉!