2019年10月21日 星期一

[Vue] 路由

簡單路由

  • Step1: 定義路由
const routes = {
  '/': Home,
  '/about': About
}
  • Step2: 在root設定
new Vue({
  el: '#app',
  data: {
    currentRoute: window.location.pathname
  },
  computed: {
    ViewComponent () {
      return routes[this.currentRoute] || NotFound
    }
  },
    render (h) { return h(this.ViewComponent) }
})

完整的官方Vue Router

https://router.vuejs.org/zh/

[Vue Loader] 簡介

Vue Loader

Vue Loader 是 webpack 的 loaderoader,可以幫助開發者用組件的概念開發 vue 專案。

若不想使用,想要達到同樣效果,可直接使用 vue cli 建立專案。

使用步驟

  • 建立npm套件記錄檔
npm init y
  • 安裝webpack
npm install webpack webpack-cli --save-dev
  • 建立預設資料夾
mkdir src
mkdir dist
  • 加入指令至package.json
"build": "webpack"
  • 加入 dist 中的 index.html
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script src="main.js"></script>
</body>

</html>
  • 加入 index.js 至 src 中
  • webpack基礎架構完成,後續進入vue環境設定
  • 安裝vue loader
npm install -D vue-loader vue-template-compiler
  • 加入web.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      // 它会应用到普通的 `.js` 文件
      // 以及 `.vue` 文件中的 `<script>` 块
      {
        test: /\.js$/,
        loader: 'babel-loader'
      },
      // 它会应用到普通的 `.css` 文件
      // 以及 `.vue` 文件中的 `<style>` 块
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    // 请确保引入这个插件来施展魔法
    new VueLoaderPlugin()
  ]
}
  • 加入 Vue root 至  index.js 中(記得安裝vue, npm install vue --D)
import Vue from 'vue'

new Vue({
    el: '#app',
    mounted: function () {
        console.log('Hello World');

    }
})
  • 加入其他轉譯相關套件
npm install babel-core babel-loader --save-dev
npm install  vue-style-loader css-loader --save-dev

*. babel-loader改成^7.1.5
  • 加入 resolve 至 webpack config 中

resolve: { 
            alias: { 
                'vue': 'vue/dist/vue.js' 
            } 
        }
  • 使用babel預設參數
npm install babel-preset-env babel-preset-vue --save-dev

加入以下設定至 package.json 中

"babel": {
    "presets": [
      "env",
      "vue"
    ]
  }

2019年10月17日 星期四

[Vue CLI] 單文件組件


  • Vue.component是global組件
  • new Vue({    el: '#app' ... }) 可定義容器
通常透過以上2點就可構成 vue 的前台站台,為了方便管理,可用單文件組件的概念來開發。

單文件組件

  • 副檔名: *.vue
  • <template></template>中放html
  • <script></script>中放js
  • <style></style>中放css
  • 同一份檔案包含三個區塊

關注點分離

關注點分離不代表文件類型分離,和其他的框架認知上有根本上的差異

Vue Loader

.vue文件需要透過 vue loader 編譯成最後結果

2019年10月16日 星期三

[Vue CLI] CLI服務

@vue/cli-service

這包程式碼提供了開發、打包的指令。

使用vue cli建立的專案內建二了指令

{
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  }
}

vue-cli-service serve [options] [entry]

啟動開發站台

options
  •   --open    在服務器啟動時打開瀏覽器
  •   --copy    在服務器啟動時將 URL 複製到剪切版
  •   --mode    指定環境模式 (默認值:development)
  •   --host    指定 host (默認值:0.0.0.0)
  •   --port    指定 port (默認值:8080)
  •   --https   使用 https (默認值:false)

vue-cli-service build [options] [entry|pattern]

打包程式碼

options
  •   --mode        指定環境模式 (默認值:production)
  •   --dest        指定輸出目錄 (默認值:dist)
  •   --modern      面向現代瀏覽器帶自動回退地構建應用
  •   --target      app | lib | wc | wc-async (默認值:app)
  •   --name        庫或 Web Components 模式下的名字 (默認值:package.json 中的 "name" 字段或入口文件名)
  •   --no-clean    在構建項目之前不清除目標目錄
  •   --report      生成 report.html 以幫助分析包內容
  •   --report-json 生成 report.json 以幫助分析包內容
  •   --watch       監聽文件變化

vue-cli-service inspect [options] [...paths]

檢查 vue cli 的 web config

[Vue CLI] 預設配置

.vuerc

在 windows 作業系統中,User/安裝過vue的登入者底下,會有一個.vuerc的檔案,裡面紀錄用vue create建立專案時,的預設配置。

2019年10月14日 星期一

[Vue CLI] 插件

vue ui

可用圖形化介面了解整個框架的全貌

vue add

  • 可在現存的vue專案中,加入第三方套件
  • 主要目的為控管vue專案的第三方套件,跟vue無關的套件不要用vue add安裝
e.g. vue add eslint

router和vuex

  • 加入router
vue add router

*. 內件基本架構,使用非常方便
  • 加入vuex
vue add vuex

vue invoke

套件已安裝,但是想改參數的時候,可以使用這個命令

e.g. 

之前已經做過這個指令 vue add eslint,但是想改eslint的參數

可以下這個指令 vue invoke eslint --config airbnb --lintOn save

2019年10月13日 星期日

[Vue CLI] 安裝

安裝Vue CLI

npm install -g @vue/cli

安裝完成後檢查版本

vue --version

建立專案

  • 命令安裝
vue create project-name
  • 介面安裝(易上手)
vue ui

快速原型開發

  • 需額外安裝service
npm install -g @vue/cli-service-global

  • 安裝完可使用以下指令
  1. vue serve
  2. vue build

2019年10月6日 星期日

[Vue] 動態組件&異步組件

動態組件

<component v-bind:is="currentTabComponent"></component>
  • 在切換component時, 預設會重新渲染DOM
  • <keep-alive></keep-alive> 可以不用重新渲染DOM
<keep-alive>
    <component v-bind:is="currentTabComponent"></component>
</keep-alive> 

異步組件

  • 在非同步, 有條件的情境下, 載入組件
Vue.component('function1', function (resolve, reject) {
    setTimeout(() => {
        resolve({
            template: `
            <div>        
                <counter></counter>
                <counter></counter>
            </div>`
        })
    }, 3000);
})

延伸關鍵字 webpack + async vue component

2019年10月3日 星期四

[Vue] 插槽 2/2

作用域插槽

  1. 父組件可以使用子組件的data
  2. 被綁定在slot上的prop稱為: 插槽 prop
  • 父組件
<my-tab>
</my-tab>
  • 子組件
Vue.component('my-tab', {
    data: function () {
        return {
            tabName: 'Default Tab Name'
        }
    },
    template: `
    <div>
    <br>
    <a style="border: 1px solid black;">
        <slot v-bind:tabName="tabName">預設內容</slot>
    </a>
    <br>
    <slot name="content"></slot>
    </div>
    `
})

自定義插槽prop名稱

  1. 在子組件上, 用v-slot可自定義插槽prop的名稱
  2. 簡寫: <my-tab v-slot="myChildVariable">...</my-tab>
  3. 簡寫和作用愈插槽寫法不可混用
  • 父組件
        <my-tab>
            <template v-slot:default="childProp">
                {{childProp.tabName}}
            </template>
        </my-tab>
  • 子組件
Vue.component('my-tab', {
    data: function () {
        return {
            tabName: 'Default Tab Name'
        }
    },
    template: `
    <div>
    <br>
    <a style="border: 1px solid black;">
        <slot v-bind:tabName="tabName">預設內容</slot>
    </a>
    <br>
    <slot name="content"></slot>
    </div>
    `
})

解構插槽prop

1. 插槽原理: 將插槽內容包括在一個傳入單個參數的函數裡,如下

function (props) {
  // 插槽內容
}

所以可以套入"解構"的概念,控制子組件的屬性
<my-tab>
    <template v-slot="{tab}">
        {{tab.tabName2}}
    </template>
</my-tab>

2. 解構之餘,同時也可重新命名屬性
<my-tab>
    <template v-slot="{tab: myTabCollection}">
        {{myTabCollection.tabName2}}
    </template>
</my-tab>

*.v-slot的縮寫符號: #


2019年10月2日 星期三

[Vue] 插槽 1/2

<slot></slot>

  1. 可以在自定義的component中,預留一個空間,給父組件插入內容。
  2. 子組件和父組件的作用域各自獨立,不可交互使用。
  • 子組件
Vue.component('my-tab', {
    template:`
    <a style="border: 1px solid black;">
        <slot></slot>
    </a>
    `
})
  • 父組件
<my-tab>
     slot content
     <br>
    {{currentTab}}
</my-tab>

後備內容

<slot></slot>中可以設定預設內容,在無任何資料時,自動顯示
  • 子組件
Vue.component('my-tab', {
    template:`
    <a style="border: 1px solid black;">
        <slot>預設內容</slot>
    </a>
    `
})
  • 父組件
<my-tab>
     slot content
     <br>
    {{currentTab}}
</my-tab>

具名插槽

  1. slot可以給定名稱(name),就可以預留多個空間給父組件。
  2. 沒有名稱(name)的slot,預設名稱: default。
  • 子組件
Vue.component('my-tab', {
    template:`
    <div>
    <a style="border: 1px solid black;">
        <slot>預設內容</slot>
    </a>
    <br>
    <slot name="content"></slot>
    </div>
    `
})
  • 父組件
<my-tab>
    slot content
    <br>
    {{currentTab}}
    <template v-slot:content>
        具名slot,給定名稱content,插入指定位置
    </template>
</my-tab>

2019年10月1日 星期二

[Vue] 自定義事件

自定義事件命名

  • 駝峰命名不會自動轉換成kebab-case,盡量使用kebab-case
e.g.

this.$emit('myCustomEvent');

// 這行不會有效果
<component v-on:my-custom-event="onEvent"></component>
  • 但是會自動轉成小寫
上面那個宣告需要使用以下寫法才監聽的到
<component v-on:myCustomEvent="onEvent"></component>

原生事件綁定至自製組件(進階)

1. 使用自製組件,綁定原生事件的作法
  • 父組件
<my-checkbox v-model="YesOrNo" v-on:focus.native="onFocus"></my-checkbox>
  • 子組件
<input
        type="checkbox"
        v-bind:checked="checked"
        v-on:change="$emit('change',$event.target.checked)"
    >
以上可以監聽子組件根元素(input)的focus事件,並觸發父組件的onFocus

2. 當根元素不是input,卻又想要做到上面這件事情時

$listeners(進階)

  • 父組件
<my-checkbox v-model="YesOrNo" v-on:click.native="onClick"></my-checkbox>
  • 子組件
computed: {
        checkboxListener: function () {
            var vm = this;
            return Object.assign({},
                this.$listeners,
                {
                    click: function (event) {
                        vm.$emit('click', event.target.checked)
                    },
                    change: function (event) {
                        vm.$emit('change', event.target.checked)
                    },
                })
        }
    },
    template: `
    <label>
    {{label}}
        <input
            type="checkbox"
            v-bind="$attrs"
            v-bind:checked="checked"         
            v-on="checkboxListener"
        >
    </label>
    `
關鍵字預留 : .sync

2019年9月29日 星期日

[Vue] Prop

prop命名


  • Vue.component('myInput', ...) 等同於 Vue.component('my-input', ...)

prop類型

  • 預設寫法
 props: ['value']
  • 型別指定寫法
    props: {
        value: any,
        prefix: String,
        ...
    }

prop特性


  • 沒給值預設值為true
<my-input type="text" v-model="title" show-prefix>


Vue.component('myInput', {
    props: {
        value: String,
        prefix: String,
        showPrefix: Boolean
    },
...

單向資料流

  • 父組件的props更新後 => 更新子元件的props
  • 子組件的props更新不會 => 更新父組件的props
  • 不應該在子組件中變更props
  • 若props的型別為Object或Array,子組件變更時,會影響到父組件

prop驗證

  • 無驗證
props: {
    value: [String, Number]
}
  • 加入驗證
props: {
    value: {
        type: [String, Number],
        required: true, // 必填
        default: 'success', // 預設值
        // 自定義驗證
        validator: function (value) {
        // 這個值必須匹配下列字符串中的一個
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    },
    ...
}

type

可以是任一原生型別
  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
也可以是自定義型別

class和style

從父組件給值時, 會和子組件合併
e.g.
  • 子組件
<input class="AAA">
  • 父組件
<my-input class="BBB">

最後渲染出來會是 <input class="AAA BBB">

2019年9月26日 星期四

[Vue] 組件註冊

組件名稱

  • Vue.component('組件名稱', {...})
  • 建議命名時
    • 全小寫
    • 用一個前缀詞加上hyphon符號(-), 避免和其他名稱重複
    • e.g. my-header

作用域

  • 全域註冊
註冊方式: Vue.component('組件名稱', {...})
  • 區域註冊
    • 好處: 在component沒被使用時,就不會被build,產生多餘的程式碼
    • 在子組件裡面也要使用的話,也需要在子組件中,再宣告一次

component宣告方式

const FooterComponent = {
    template: '<div>copyright @ blabalbala</div>'
}

根組件宣告方式

new Vue({
  ...
  components: {
    'my-footer': FooterComponent
  }
 ...
})

模塊系統

全域組件
  • 將各個component獨立成一個檔案,匯入匯出在根組件前載入
局部組件
  • 若有配合webpack或babel再深入研究
關鍵字: require, import

[Vue] 組件基礎 2/2

組件的HTML規則


  • 只能有一個根元素
e.g. 根結點不能二個元素並列, 一定要有明確的一個根結點
  • 不行:
<h1></h1>
<div></div>
  • 可以: (再包一層)
<div>

    <h1></h1>
    <div></div>
</div>
  • 模板字符串(``) 不支援IE, 需用折行轉譯字符代替
  • 不支援IE
Vue.component('component-name', {
template:`content
                line2
                line3`
}
  • 可支援IE
Vue.component('component-name', {
template:"content\
                line2\
                line3"
}

監聽子組件事件

子組件向外發出事件的方法
  • 子組件
Vue.component('my-header', {
    props: ['title'],
    template: `<div>
    <h1>{{title}}</h1>
    <button v-on:click="$emit('event-emit-test')">event emit</button>
</div>
    `
})
  • 父組件
<my-header title="Vue練習" @event-emit-test="catchClickCount+=1"></my-header>

*. $emit('事件名稱')
*. 接收方用事件名稱直接接收

監聽子組件事件(含參數傳遞)

  • 子組件
Vue.component('my-header', {
    props: ['title'],
    template: `<div>
    <h1>{{title}}</h1>
    <button v-on:click="$emit('event-emit-test',2)">event emit</button>
</div>
    `
})
  • 父組件
<my-header title="Vue練習" @event-emit-test="catchClickCount+=$event"></my-header>

v-model

v-model 就是一個bind和一個event組成的
  • 子組件
Vue.component('my-input', {
    props: ['value'],
    template: `
    <div>
    Hi~~~my input
    <input
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
    />
    </div>
    `
})
  • 父組件
<my-input v-model="variableName"></my-input>

插槽(slot)

可在自定義的組建中預留空間, 讓父組件放置
  • 子組件
Vue.component('my-block', {
    template: `
    <div class="block">
        <slot></slot>
    </div>
    `
})
  • 父組件
<my-block>
    // 把內容裝進來
</my-block>

動態組件

<component v-bind:is="要綁定的組件"></component>
要綁定的組件有二種用法
  • 組件的名稱
  • 組件本身

其他關鍵字

  • vue is
is="這邊可塞入component"
  • 字符串 (例如:template: '...')
  • 單文件組件 (.vue)
  • <script type="text/x-template">

2019年9月25日 星期三

[Vue] 組件基礎 1/2

Vue的組件(Component)使用

  • 可透過 Vue.component 來自定義組件
Vue.component('counter', {
data: function () {
    return {
        count: 0
    }
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

  • 要在 new Vue({ el: '#app' }) 的作用愈中才能使用

<div id="app">
<counter></counter>
</div>

  • new Vue(...)中有的方法Vue.component(...)中絕大多數都有
    • e.g. data, computed, watch, methods 生命週期鉤子(life cycle hook)等
  • Vue.component(...)的data是函數

組件註冊

分為二種類型
  • 全域註冊
    • 顧名思義就是在根組件之下任何地方皆可使用
    • 透過 Vue.component(...)產生
  • 局部註冊

Prop

  • 傳入參數給組件
  • 可搭配v-for v-if ...等指令使用

2019年9月23日 星期一

[Vue] 表單輸入綁定

v-model

可用在
  • <input>
<input v-model="userName" placeholder="user name">
<p>User name is: {{userName}}</p>
  • <textarea>
<textarea v-model="remark" placeholder="remark"></textarea>
<p style="white-space: pre-line">{{remark}}</p>
  • <input type="checkbox"> 
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{checked}}</label>
  • group <input type="checkbox"> 
<input type="checkbox" id="memo1" value="memo1" v-model="checkedMemo">
<label for="memo1">Memo1</label>
<input type="checkbox" id="memo2" value="memo2" v-model="checkedMemo">
<label for="memo2">Memo2</label>
<input type="checkbox" id="memo3" value="memo3" v-model="checkedMemo">
<label for="memo3">Memo3</label>
<p>Checked Memo: {{checkedMemo}}</p>
  • <input type="radio">
<input type="radio" id="first" value="first" v-model="picked">
<label for="first">first</label>
<input type="radio" id="second" value="second" v-model="picked">
<label for="second">second</label>
<p>Picked: {{picked}}</p>
  • <select>
<select v-model="selected">
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>Selected: {{selected}}</p>
  • group <select>
<select v-model="selected2" multiple>
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>Selected: {{selected2}}</p>

修飾符

  • .lazy
    • onchange時才改變值
  • .number
    • 將值轉換為number, 轉換失敗變成預設值
  • .trim
    • 去除左右空白

[Vue] 事件處理

v-on

  • v-on:事件名稱="簡易邏輯"; e.g. v-on:click="total = total + 1"
  • v-on:事件名稱="自定義事件"; e.g. v-on:click="onClick"
  • v-on:事件名稱="自定義事件(傳入參數)"; e.g. v-on:click="doSomething(var1)"
  • v-on:事件名稱="自定義事件(傳入參數, $event)"; $event為原生DOM事件

事件修飾符

常見的修飾符
  • .stop
    • 停止propogation
    • event.stopPropagation()的意思
  • .prevent
    • 停止default event
    • event.preventDefault()的意思
  • .capture
    • 使用capture監聽事件
    • 由外而內觸發事件(預設是冒泡, 由內而外)
  • .self
    • 只處理單一層DOM的事件
  • .once
    • 只觸發一次事件
  • .passive
    • 被動監聽scroll

2019年9月19日 星期四

[Vue] 列表渲染

v-for

  • 可以額外顯示 index
  • in 可改 of

index.html

        <ul>
            <li v-for="(item, index) of items">
                {{item.message}}
            </li>
        </ul>

index.js

var app = new Vue({
    el: '#app',
    data: {
    items: [
         { message: 'message 1' },
        { message: 'message 2' }
    ]
}
})

v-for 可和 Object 一起使用

  • 可以額外顯示屬性名稱
  • 可以額外顯示 index
  • 順序是依照 Object.keys() 的順序, 不保證每個瀏覽器順序相同
  • 建議和 "key" 屬性相互搭配,, 避免順序變動時, 顯示異常

index.html

        <ul>
            <li v-for="(value, name) in object">
                {{value}}
            </li>
        </ul>

index.js

var app = new Vue({
    el: '#app',
    data: {
     object: {
         name: 'Shawn',
         sex: 'male',
         phone: '0912345678'
     }
}
})


2019年9月16日 星期一

[Vue] 條件渲染

v-if

  • 可搭配 v-else 使用
    • 必須緊跟在 v-if 或 v-else-if 之後
  • 也可搭配 v-else-if 使用
    • 必須緊跟在 v-if 之後
  • 可搭配<template>使用
    • 實際渲染時, 不會存在的元素

index.html

<div v-if="showHint">看情況顯示文字</div>

index.js

var app = new Vue({
    el: '#app',
    data: {
showHint: true
}
})

渲染機制

  • v-if, v-else 在使用時, 重複的內容"不會"重新渲染
  • 若要重新渲染, 應加上"key"屬性
  • 沒被加上key的元素, 依然會重複使用
        <div v-if="showHint">
            看情況顯示文字 <br>
            <input type="text" key="input1">
        </div>
        <div v-else>
            Hi v-else顯示 <br>
            <input type="text" key="input2">
        </div>

v-show

  • 單純的css display切換
  • DOM在一開始就會渲染

v-if , v-show

  • 頻繁的切換用 v-show
  • v-if 耗用的資源較多

v-if 和 v-for 同時使用

  • v-for先執行, v-if後執行
  • 官方不建議這樣使用

2019年9月15日 星期日

[Vue] Class與Style綁定

Class動態綁定(v-bind:class-name)

  • 動態class可和一般class共存
  • 可綁定一個或多個class
  • vue component 也可套用

index.html

        <div v-bind:class="{'name-block':true}">
            內容文字
<button @click="changeColor">Change background color</button>
        </div>

index.css

.name-block {
  background-colorantiquewhite;
  margin8px;
  padding8px;
}

.dark-theme {
  background-colorbrown;
  colorwhite;
}

index.js

var app = new Vue({
    el: '#app',
    data: {
isDark: false
},
methods: {
changeColor: function () {
            this.isDark = !this.isDark
        }
}
)

Class動態綁定 - 2

  • 可將整個class object放在javascript中

index.html

        <div class="block age-block" :class="classObject">
            你幾歲?
            <div>Reply: {{reply}}</div>
            <input type="text" v-model="age">
        </div>

index.css

.block {
  margin8px;
  padding8px;
}
.age-block {
  background-colorbisque;
}

index.js

var app = new Vue({
computed: {
        classObject: function () {
            return { 'dark-theme': this.isDark }
        }
    }
})

Inner Style動態綁定(v-bind:style-name)

  • 若有需要的話,vue會自動補上瀏覽器引擎前綴詞, e.g. transform

index.html

        <div class="block hello-world-block" :style="{fontSize: fontSize + 'px'}">
            <input type="text" v-model="title">
            <div>{{title}}</div>
            <div>Reverse Title: {{reverseTitle}}</div>
        </div>

index.css

.hello-world-block {
  background-colorburlywood;
}

index.js

var app = new Vue({
    el: '#app',
    data: {
     fontSize: 30
}
})

2019年8月26日 星期一

[Vue] 模板語法 2/2

計算屬性(computed)

index.html

<div>Reverse Title: {{reverseTitle}}</div>

index.js

Vue({
  data: {
      title: 'Test'
  },
  computed: {
    // 自定義屬性
        reverseTitle: function () {
            return this.title.split('').reverse().join('')
        }
  }
})

計算屬性 v.s. 方法

  methods: {
        reverseTitle: function () {
            return this.title.split('').reverse().join('')
        }
  }


  computed: {
    // 自定義屬性
        reverseTitle: function () {
            return this.title.split('').reverse().join('')
        }
  }
  • methods 每次渲染都會更新,保持最新的值,但使用較多資源
  • computed 會緩存,不一定是最新的值,使用較少資源

計算屬性結合 getter / setter

data: {
    firstName: 'Shawn',
    lastName: 'Tseng'
},
computed: {
        fullName: {
            get: function () {
                return this.firstName + ' ' + this.lastName
            },
            set: function (newValue) {
                var name = newValue.split(' ');
                this.firstName = name[0];
                this.lastName = name[name.length - 1];
            }
        }
}
  • 在 fullName 更新時,也會觸發 set ,更新 firstName 和 lastName

監聽器(watch)

  data: {
    age: '',
    reply: '',
  },
  watch: {
      age: function (oldValue) {
        this.reply = '你的年紀:' + oldValue;
      }
  }
  • 在age變動時,會執行watch的邏輯,非常消耗資源
  • 在需要串接後端的情境常使用

2019年8月20日 星期二

[Vue] 模板語法 1/2

常見的模板語法

  • Mustache(雙大括號)
只要變數更新,模板就會更新

{{ var }}

  • 一次性綁定
只有第一次會更新模板

<div v-once>{{showHint}}</div>

  • HTML 解析

<div v-html="rawHtml"></div>

*. 使用v-html正確解析 HTML內容

  • 屬性綁定
<input type="text" v-bind:disabled="!canTypeIn">

*. 使用v-bind綁定 HTML 元素屬性

常見的指令

  • v-if
<div v-if="showHint">看情況顯示文字</div>

  • v-bind:屬性名稱="要綁定的變數"
<span v-bind:title="loadTime">
    滑鼠移置文字上,顯示'網頁啟動時間'
</span>

*. 縮寫 :bind:屬性名稱="要綁定的變數"

  • v-on:事件名稱="要綁定的方法"
<button v-on:click="switchShowHint">開關</button>

*. 縮寫 @click="要綁定的方法"



2019年8月18日 星期日

[Vue] new Vue 的實體

new Vue()

var vm = new Vue({ // 參數 })

  • vm: viewModel的意思,概念源自於MVVM架構。

參數

  • data
var data = {
    title: 'Hello World'
}

var vm = new Vue({
    data: data
})

Vue 會把變數 data和變數 vm雙向綁定
data.title === vue.title // true
data.title = '改值時vm.title也會改';
vm.title = '改值時data.title也會改';

結論: data 和 vm 共用記憶體空間

DOM渲染注意事項

1.
透過
var vm = new Vue({
    data: data    
})
新增的屬性,都會被監聽,變更時會渲染到畫面上

2.
new Vue() 之後才新增的屬性,都不會被監聽
e.g.

vm.newProperty = 'test'; // newProperty 不會被監聽

3.
根據1.2.的特性,未來才會用到的屬性,就需要在一開始設置初始值
e.g.
var data = {
    futureProperty:''
}

4.
Object.freeze() 可以使物件變成唯讀,不被監聽
e.g.
Object.freeze(data); // 意即data不會被監聽,不會更新到畫面上

Vue提供的屬性、方法

vue提供的屬性方法前面會有前綴符號 $
e.g.
  • vm.$data
vm的data
  • vm.$el
vm的DOM
  • vm.$watch('property',function(newValue, oldValue){ // callback })
可監聽某個property

Vue提供的hook

在 Vue 的生命週期過程中,提供的不同的 hook 給使用者,全景未來說明

e.g.
new Vue({
    created: function(){
        console.log(this.property);
    }
})


2019年8月15日 星期四

[Vue] 元件化 / 屬性傳入

元件

元件最大的好處就是能重複使用
  • index.html
<div id="app">
<ul>
    <li v-for="data in dataList">
        {{data.text}}
    </li>
    <list-item></list-item>
    <list-item></list-item>
    <list-item></list-item>
</ul>
</div>
  • index.js
Vue.component('list-item', {
    template: '<li>第N個項目</li>'
})
var app = new Vue({
    el: '#app'
})

屬性傳入(父元件=>子元件)

  • index.html
<ul>
    <list-item v-for="data in dataList" v-bind:item="data">
    </list-item>
</ul>
  • index.js
Vue.component('list-item', {
    props:['item'],
    template: '<li>{{item.text}}</li>'
})

var app = new Vue({
    el: '#app',
    data: {
        dataList: [
            { text: 'A項目' },
            { text: 'B項目' },
            { text: 'C項目' }
        ]
    }
})

2019年8月14日 星期三

[Vue] If / For / Event / Model(two-way binding)

條件

  • index.html
<div v-if="showHint">看情況顯示文字</div>
  • index.js
data: {
    showHint:true
}

迴圈

  • index.html
<ul>
    <li v-for="data in dataList">
        {{data.text}}
    </li>
</ul>
  • index.js
data: {
    dataList: [
        { text: '第一個項目' },
        { text: '第二個項目' },
        { text: '第三個項目' }
    ]
}

事件綁定

  • index.html
<button v-on:click="switchShowHint">開關</button>

*.v-on:事件名稱
  • index.js
methods: {
    switchShowHint: function () {
        this.showHint = !this.showHint
    }
}

雙向綁定

事件綁定

  • index.html
<input type="text" v-model="title">

*.v-on:事件名稱
  • index.js
data: {
    title: 'Hello World'
}


2019年8月13日 星期二

[Vue] 建立專案 / 變數顯示綁定 / 屬性綁定

關於 Vue 框架的使用方式

Step1. 加入 Vue 的核心函式庫

  • 開發版
<!-- 包含了有幫助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  • 正式版
<!-- 優化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

Step2. 加入樣板語法

  • index.html
<div id="app">
    {{title}}
</div>
  • index.js
var app = new Vue({
    el: '#app',
    data: {
        title: 'Hello World'
    }
})

Step3. 元素屬性綁定

  • index.html
<span v-bind:title="loadTime">
    滑鼠移置文字上,顯示'網頁啟動時間'
</span>

*.v-bind: 一種指令,可將變數綁定至元素屬性上
  • index.js
data: {
    loadTime: '網頁啟動於:' + new Date().toLocaleString()
}

2019年8月11日 星期日

[Back To Basic] CSS Grid Layout

Grid Layout

不需要 float 和 positioning 也可排版。

Grid Elements

包含一個父元素(parent element)和多個子元素(child elements)。

Step1. 設定Grid顯示

display: grid;
display: inline-grid;

Step2. 設定屬性

  • 設定Gap
    • grid-column-gap: 20px;
    • grid-row-gap: 20px;
    • grid-gap: 20px;
  • 設定lines(跨欄)
    •   grid-column-start: 1;
    •   grid-column-end: 3;
    •   grid-row-start: 2;
    •   grid-row-end: 4;

2019年8月7日 星期三

[Back To Basic] CSS Media Queries

Media Type

css2曾推出@media規則,可根據不同裝置,套用不同的css樣式,但沒有太多裝置支援此規則

Media Queries

css3延伸 Media Type 的想法,依據下列規則,達成目的。
  • 視窗寬高
  • 設備寬高
  • 設備方向
  • 解析度

CSS3 Media Type

  • all
所有設備
  • print
印表機
  • screen
螢幕
  • speech
螢幕閱讀機

語法

@media not|only MediaType and (expressions) { /* 套用條件 */
/* 要套用的CSS樣式 */
}
e.g.
@media screen and (min-width: 960px) { /* 螢幕寬度在960以上皆套用 */
  .block1 {
    background-color: blueviolet;
  }
}

2019年8月6日 星期二

[Back To Basic] CSS Flexbox 2/2

align-content: 垂直空間對齊方式

完全置中

排版常常會遇到完全置中的情境,flex 的處理方式

2019年8月5日 星期一

[Back To Basic] CSS Flexbox 1/2

Flexbox 出來之前的4種排版模式

  • Block: 區塊
  • Inline: 段落文字
  • Table: 二維表格資料
  • Positioned: 明確定位的元素

Flexbox

不使用 float 和 positioning,也能更容易設計出更有彈性的版面

使用方法

Step1 容器設定
.container {
  display: flex;
}

Step2 屬性設定

flex-direction: 排列方向
flex-wrap: 擠壓時是否換行
flex-flow: flex-direction flex-wrap

justify-content: 水平對齊
align-items: 垂直對齊

2019年8月4日 星期日

[Back To Basic] CSS Box Sizing

在計算元素的寬高時,應該用哪種計算方式

  • 預設

width + padding + border = 實際寬度
height + padding + border = 實際高度

這種作法在指定寬和高時,實際的寬高會比預期的還要大,這樣的現象會讓排版變得困難。

解決方式

box-sizing: border-box;
  • box-sizing
width - padding - border = 實際寬度
height - padding - border = 實際高度

可加上以下語法通解

* {
  box-sizing: border-box;
}

2019年7月30日 星期二

[Back To Basic] CSS var()

宣告變數

在 CSS 中宣告變數的做法
  • 區域變數
    • 在 selector{} 中直接宣告,有效範圍就在這個 selector 中
  • 全域變數
    • 在 :root{} 中宣告
    • 在 body{} 中宣告
*. 變數語法: --variableName
*. 變數名稱的大小寫不同,視為不同

var(variableName, value)

  • variableName: 變數名稱
  • value: 備用值(指定變數值無效時使用)

2019年7月29日 星期一

[Back To Basic] CSS User Interface

User Interface

  • resize
容器有調整大小的功能,這個屬性可以控制水平縮放或垂直縮放

可選擇的屬性值:
    • horizontal
    • vertical
    • both
    • none
*. 若瀏覽器預設<textarea>有resize的功能,可以用none關閉
  • outline-offset
增加 outline 和 border 中間的空間
    • outline 不屬於 element 的一部分(outline 和 element 不在同一個維度)
    • outline 可能會覆蓋其他內容
    • element 的寬和高,不被 outline 寬度影響

2019年7月22日 星期一

[Back To Basic] CSS object-fit

object-fit

指定圖片、影片,適應容器的模式。
  • fill 
填滿容器,視情況放大或縮小(圖片、影片會被壓縮或拉長)
  • contain
以容器的大小為主,保持長寬比,填入圖片、影片(圖片會變小)
  • cover
保持長寬比,但是會裁減圖片
  • none
無適應能力(不會放大縮小),無視容器
  • scale-down
none 和 contain 取二者中較小

2019年7月21日 星期日

[Back To Basic] CSS 圖片樣式

可搭配的屬性

  • 圓角: border-radius
  • 邊框: border
  • 留白: padding
  • 陰影:box-shadow
  • 透明度: opacity
  • 濾鏡: filter

可搭配的狀態

  • hover

RWD

  • 最大寬度: max-width

置中

{
  width: 50%; /* 可以調整 */
  display:block;
  margin-left: auto;
  margin-right: auto;
}

2019年7月18日 星期四

[Back To Basic] CSS Tooltip

Tooltip

在滑鼠移到某個元素上時,給予額外的資訊。

用純css做出tooltip。

2019年7月17日 星期三

[Back To Basic] CSS Animations

使用純 css 做動畫。

Animations

  • 可讓元素從一個樣式逐漸改變成另一個樣式
  • 很多 css 屬性皆可應用
  • 動畫次數可指定
  • 影格的概念很重要

@keyframes

@keyframes 影格名稱 {
  from {
    background-color: yellow;
  }
  to {
    background-color: blue;
  }
}
  • 從from變化到to
  • 綁定影格到元素上
animation-name: 影格名稱;
  • 指定影格總秒數
animation-duration: 秒數; (預設為0秒,所以沒有設定就不會有動畫)

animation-delay

  • 動畫延遲n秒後開始
  • 可以是負值

animation-iteration-count

  • 動畫執行的次數 e.g. 1 2 3...
  • 無限: infinite

animation-direction

指定動畫的方向
  • normal(預設值): 向前
  • reverse: 倒轉
  • alternate: 先正常播放後倒轉
  • alternate-reverse: 先倒轉後正常播放

animation-timing-function

速度曲線
  • ease(預設值): 慢 快 慢
  • linear: 中 中 中
  • ease-in: 慢 中 中
  • ease-out: 中 中 慢
  • ease-in-out: 慢 漸快 漸慢 慢
  • cubic-bezier(n,n,n,n): 自行指定貝茲曲線,決定速度

animation-fill-mode

在影格沒有播放時,可指定一個樣式
  • none(預設值)
無任何樣式
  • forwards
保留最後一個影格的樣式
  • backwards
保留第一個影格的樣式
  • both
遵循 forwards 和 backwards 的規則,延展動畫的屬性值

animation(縮寫)

動畫名稱, 動畫總時間 速度曲線 動畫延遲 動畫次數 動畫方向 動畫填滿模式 播放狀態

name duration timing-function delay iteration-count direction fill-mode play-state;


[Back To Basic] CSS Transitions

Transition

指定過場時間,讓屬性時改變的時候更平順。

先決條件

  • 決定過場的屬性 e.g. color, width...
  • 決定過場的時間 e.g. 2s
*.如果沒有決定過場的屬性,不會有過場的效果,因為過場的時間預設為0秒

*.可以同時指定2個以上要過場的屬性

速度曲線

語法: transition-timing-function

可指定的屬性值,過場簡略分為三部分,開始 / 過程 / 結束
  • ease(預設值): 慢 快 慢
  • linear: 中 中 中
  • ease-in: 慢 中 中
  • ease-out: 中 中 慢
  • ease-in-out: 慢 漸快 漸慢 慢
  • cubic-bezier(n,n,n,n): 自行指定貝茲曲線,決定速度

延遲過場

語法: transition-delay

其他

*.過場(transition)和變形(transform)可以並用

2019年7月14日 星期日

2019年7月11日 星期四

[Back To Basic] CSS 2D Transforms

CSS transform

可以對元素做以下操作
  • 移動
  • 旋轉
  • 縮放
  • 傾斜

語法

  • transform
  • -ms-transform: IE9
  • -webkit-transform: Safari 9

方法

  • translate()
移動元素: 從目前位置移動指定的 x, y值
  • rotate()
旋轉元素: 旋轉指定的角度
  • scale()
縮放元素: 依據指定的參數倍數縮放
  • scaleX()
縮放元素寬度: 依據指定的參數倍數縮放寬度
  • scaleY()
縮放元素高度: 依據指定的參數倍數縮放高度
  • skew()
傾斜元素: 依據指定的角度傾斜元素
  • skewX()
傾斜元素X軸: 依據指定的角度傾斜X軸
  • skewY()
傾斜元素Y軸: 依據指定的角度傾斜Y軸
  • matrix()
結合以上所有功能,參數: matrix(scaleX(),skewY(),skewX(),scaleY(),translateX(),translateY())


2019年7月10日 星期三

[Back To Basic] CSS Web Fonts

Web Fonts

  • 可以使用: 沒有安裝在使用者電腦的字體
  • 想要使用的字體,可以從server端自動下載至client端
  • 關鍵字: @font-face
e.g.
@font-face {
  font-family: myFirstFont; /* 定義字體的名字 */
  src: url(sansation_light.woff); /* 設定字體檔案的來源 */
}

*. url 要用小寫,否則 IE 可能會有問題

字體種類

  • .ttf
    • mac, windows皆支援
    • 所有主流瀏覽器皆支援(ie8不支援, ie9有條件支援)
    • 可能有版權問題
    • 無壓縮(檔案較大)
  • .otf
    • mac, windows皆支援
    • 所有主流瀏覽器皆支援(ie8不支援, ie9有條件支援)
    • ttf的擴充
  • .woff
    • mac, windows皆支援
    • 所有主流瀏覽器皆支援(ie8不支援, ie9有條件支援)
    • 有壓縮(檔案較小)
  • .woff2
    • 並未受到廣泛的支持
    • 是woff的加強版,檔案更小
  • .svg
    • 只支援safari特定版本
  • .eot: 微軟開發
    • 只支援IE

2019年7月9日 星期二

[Back To Basic] CSS Text Effects


text-overflow

文字超出容器時如何處理
  • clip: 直接裁斷
  • ellipsis: 刪節號後面省略

word-wrap

"單字"超出容器時如何處理
  • break-word: 單字可裁斷

word-break

容器內,語句斷行的規則
  • keep-all: 保留每個單字完整
  • break-all: 只要超出邊界即裁斷單字

writing-mode

文字的書寫方向,以及水平書寫或垂直書寫

2019年7月8日 星期一

[Back To Basic] CSS Shadow Effects

CSS的陰影效果

共包含二項
  • text-shadow
  • box-shadow

text-shadow

語法: h-shadow v-shadow blur-radius color|none|initial|inherit;

  • h-shadow 水平陰影
  • v-shadow 垂直陰影
  • blur-radius 模糊邊界
  • color 陰影顏色

box-shadow

語法: none|h-offset v-offset blur spread color |inset|initial|inherit;


  • h-offset 水平移動
  • v-offset 垂直移動
  • blur 模糊邊界
  • spread 傳播半徑(可增減陰影大小)
  • color 陰影顏色

[Back To Basic] CSS Gradients

Gradient 可以讓N種顏色之間的過渡更和緩,漸層的概念。

CSS 有二種 gradients

  • linear gradient
語法: background-image: linear-gradient(direction, color-stop1, color-stop2, ...);
  • 方向: 上到下(預設) e.g. to bottom, to bottom right, to right ...
  • 顏色1
  • 顏色2
  • ...
*. 方向也可用角度取代
e.g.
background-image: linear-gradient(55deg, red, yellow);

*. 也可配合透明色使用
  • radial gradient
語法: background-image: radial-gradient(direction, color-stop1, color-stop2, ...);
  • 形狀大小位置: 橢圓形 + 平均間隔(預設)
  • 顏色1
  • 顏色2
  • ...

2019年7月4日 星期四

[Back To Basic] CSS Multiple Backgrounds

讓多個圖片在同一個元素中

語法

做法一:
background-image: 圖片來源1, 圖片來源2
background-position: 圖片1位置, 圖片2位置
background-repeat: 圖片1重複方式, 圖片2重複方式

做法二(縮寫):
background: 圖片來源1 圖片1位置 圖片1重複方式, 圖片來源2 圖片2位置 圖片2重複方式

*.用逗號分隔多張圖片

*.來源1 會在來源2上方,以此類推

語法: background-size

可以決定背景圖片的大小,包含兩個特殊值
  • contain
背景圖 > 所在內容: 但卻需要將背景圖完整呈現,用contain,使背景圖縮小至內容的大小
  • cover
背景圖 < 所在內容: 而背景圖又不適合使用repeat,用cover,使背景圖放大至內容的大小,但此方法容易使背景圖因放大而失真

*. 也可配合多圖片,用逗號分隔即可

滿版背景圖片

能夠達成以下條件
  • 圖片滿版
  • 在需要的時候擴展圖片
  • 圖片置中於整個頁面
  • 不會產生 scrollbar
background: url(img_man.jpg) no-repeat center fixed; 
background-size: cover;

語法: background-origin(位置會受到background-position影響)

指定圖片繪製的起始位置
  • border-box
以左上border當起點
  • padding-box(預設值)
以左上padding邊界當起點
  • content-box
以左上content邊界當起點

語法: background-clip

指定圖片顯示的起始位置
  • border-box(預設值)
border之外
  • padding-box
padding之外
  • content-box
content之外

2019年7月1日 星期一

[Back To Basic] CSS border images

Border Image

CSS可以設定圖片作為元素的邊框

語法

border-image: 圖片來源 切分方式 圖片拼接方式(重複、延展...)

*.圖片會被切分成九份,各自對應角落、四邊及中間

*.一定要設定 border

2019年6月30日 星期日

[Back To Basic] CSS rounded corner

rounded corner(圓角)

CSS可以設定元素的圓角半徑

語法

border-radius: 左上 右上 右下 左下

border-radius: 左上 右上+左下 右下

border-radius: 左上+右下  右上+左下

border-radius: 左上+右下+右上+左下

*.可以做八圓角

*.可以用來做橢圓形

source code

2019年6月27日 星期四

[Back To Basic] CSS Specificity

如果有多個 CSS 規則套用在同一個元素上時,確定最後要套用哪一個的規則就是 Specificity

每個選擇器都有特定的層級,優先順序為:

Inline styles > ID > class、attributes、pseudo-class > element、pseudo-element

*. 如果優先順序相同,就看哪個規則在 style sheet 比較下面

2019年6月26日 星期三

[Back To Basic] CSS Units

數值&單位


  • 數值和單位之間不能有空白
e.g. 18px
  • 數值為0的話,單位可以省略
  • 有一些 CSS 屬性,數值可以為負值


長度單位有二種類型

  • 絕對長度
適合用於已經知道要輸出的媒介,例: 印表機的輸出版面配置

絕對長度單位:
    • cm: 公分
    • mm: 毫米
    • in: 英吋
    • px: 像素
    • pt: 點
    • pc: 派卡
  • 相對長度
在不同裝置中,有更好的延展性

相對長度單位:
  • em: 相對於字體大小
  • ex: 相對於字體高度
  • ch: 相對於"0"的寬度
  • rem: 相對於根元素的字體大小
  • vw: 相對於viewport寬度的1%
  • vh: 相對於viewport高度的1%
  • vmin: 相對於viewport較小的維度
  • vmax: 相對於viewport較大的維度
  • %: 相對於父元素
*.Viewport 就是瀏覽器window的大小