--- tags: VUE --- 【VUE】Vue元件|修飾符|指令 === # 元件註冊 [文件](https://cn.vuejs.org/v2/guide/components-registration.html) ```javascript= // 局部註冊 var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA }, // ... } ``` > 元件內資料與外層不同 # X-template ## 0. html ```htmlmixed= <!-- 以下寫法tr不會被包在table>tbody中 --> <table> <tbody> <row-component v-for="(item, key) in data" :person="item" :key="key"></row-component> </tbody> </table> ``` > 使用 is 掛載 template ```htmlmixed= <!-- is寫法 改寫 --> <tr is="row-component" v-for="(item, key) in data" :person="item" :key="key"></tr> ``` ## 1. js - Vue.component('元件名稱', {}) ```htmlmixed= <script type="text/x-template" id="rowCompointeTemplate"> <tr> <td>{{ person.name }}</td> <td>{{ person.cash }}</td> <td>{{ person.icash }}</td> </tr> </script> ``` ```javascript Vue.component('row-component', { props: ['person'], template: '#rowCompointeTemplate' }) ``` ## 2. 局部註冊 ```javascript var child = { props: ['person'], template: '#rowComponentTemplate' } var app = new Vue({ el: '#app', components: { "row-component": child } }); ``` --- # Props: 由外而內傳入資料 - 單向數據流 ```htmlmixed= <script type="text/x-template" id="photo"> <div> <img :src="imgUrl" class="img-fluid" alt="" /> <input type="text" class="form-control" v-model="newUrl"> </div> </script> ``` ```htmlmixed= <script> Vue.component('photo', { props: ['imgUrl'], template: '#photo', data() { return { newUrl: this.imgUrl } } }) </script> ``` - 資料匯入的時間差 - 利用v-if讓元件產生時間往後移,等資料匯入 ```htmlmixed= <card :user-data="user" v-if="user.phone"></card> ``` - 物件傳參考特性 - 維持狀態與生命週期 ```htmlmixed= <keep-alive> <keep-card v-if="isShow"> </keep-card> </keep-alive> ``` ### props 型別 - 預設型別與預設值 ```htmlmixed= <script> props: { cash2: { type: Number, default: 200 } }, </script> ``` - 靜態屬性 > 在靜態屬性傳數值時,傳入的為string ```htmlmixed= <prop-type cash2="300"></prop-type> <!-- 在靜態屬性傳數值時,傳入的為string --> ``` - 動態屬性 ```htmlmixed= <prop-type :cash2="300"></prop-type> ``` --- # emit: 向外層傳遞事件(Data) ```htmlmixed= <div id="app"> <h2>透過 emit 向外傳遞資訊</h2> 我透過元件儲值了 {{ cash }} 元 <button-counter v-on:increment="incrementTotal"></button-counter> <hr> <button-counter v-on:increment="incrementTotal"></button-counter> </div> <script> Vue.component('buttonCounter', { template: `<div> <button @click="incrementCounter" class="btn btn-outline-primary">增加 {{ counter }} 元</button> <input type="number" class="form-control mt-2" v-model="counter"> </div>`, data: function() { return { counter: 1 } }, methods: { incrementCounter() { this.$emit('increment', Number(this.counter)) } } }); var app = new Vue({ el: '#app', data: { cash: 300 }, methods: { incrementTotal(newNumber) { this.cash += newNumber; } } }); </script> ``` --- # Slot 插槽替換 #### 具名插槽 ```htmlmixed= <named-slot-component> <header slot="header">替換的 Header</header> <template>替換的 Footer</template> <template slot="btn">按鈕內容</template> <p>其餘的內容</p> </named-slot-component> <script type="text/x-template" id="namedSlotComponent"> <div class="card my-3"> <div class="card-header"> <slot name="header">這段是預設的文字</slot> </div> <div class="card-body"> <slot> <h5 class="card-title">Special title treatment</h5> <p class="card-text">With supporting text below as a natural lead-in to additional content.</p> </slot> <a href="#" class="btn btn-primary"> <slot name="btn">spanGo somewhere</slot> </a> </div> <div class="card-footer"> <div>這是預設的 Footer</div> </div> </div> Vue.component('named-slot-component', { template: '#namedSlotComponent', }); </script> ``` # is ### 使用is顯示單一組件 ```htmlmixed= <primary-component :data="item"></primary-component> <!-- 與上方相同效果 --> <div is="primary-component" :data="item"></div> ``` ### 使用 is 動態切換組件 ```htmlmixed= <div :is="current" :data="item"></div> ``` ```javascript= Vue.component('primary-component', { props: ['data'], template: '#primaryComponent', }); Vue.component('danger-component', { props: ['data'], template: '#dangerComponent', }); var app = new Vue({ el: '#app', data: { item: { header: '這裡是 header', title: '這裡是 title', text: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Enim perferendis illo reprehenderit ex natus earum explicabo modi voluptas cupiditate aperiam, quasi quisquam mollitia velit ut odio vitae atque incidunt minus?' }, current: 'primary-component' } }); ``` ```htmlmixed= <script type="text/x-template" id="primaryComponent"> <div class="card text-white bg-primary mb-3" style="max-width: 18rem;"> <div class="card-header">{{ data.header }}</div> <div class="card-body"> <h5 class="card-title">{{ data.title }}</h5> <p class="card-text">{{ data.text }}</p> </div> </div> </script> <script type="text/x-template" id="dangerComponent"> <div class="card text-white bg-danger mb-3" style="max-width: 18rem;"> <div class="card-header">{{ data.header }}</div> <div class="card-body"> <h5 class="card-title">{{ data.title }}</h5> <p class="card-text">{{ data.text }}</p> </div> </div> </script> ``` # [vue] Vue 修飾符 ## v-on: event #### 事件修飾符 - .stop - 調用 event.stopPropagation()。 - .prevent - 調用 event.preventDefault()。 - .capture - 添加事件偵聽器時使用 capture 模式。 - .self - 只當事件是從偵聽器綁定的元素本身觸發時才觸發回調。 - .once - 只觸發一次回調。 ```html // example @click.once="trigger('div')" ``` #### 按鍵修飾符 - .{keyCode | keyAlias} - 只當事件是從特定鍵觸發時才觸發回調。 - 別名修飾 - .enter, .tab, .delete, .esc, .space, .up, .down, .left, .right - 修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器 - .ctrl, .alt, .shift, .meta ```html <input type="text" class="form-control" v-model="text" @keyup.shift.enter="trigger('shift + Enter')"> ``` # [vue] Vue指令 ### v-bind - 用來綁定動態資料 - 可以省略,如 :href="link" ```html <a v-bind:href="'https://' + link" target="_blank"> {{link}} </a> <a :href="'https://' + link" target="_blank"> {{link}} </a> ``` ### v-for, v-if ```html <li v-for="(item, index) in list" v-if="item.age < 25"> {{ index+1 }}. {{ item.name }} 年齡是 {{ item.age }} 歲 </li> ``` ### v-on - 簡寫: @ - v-on 是一個事件監聽器 ```html <button class="btn btn-primary mt-1" v-on:click="reverseText">反轉字串</button> ``` ```javascript methods: { reverseText() { this.newText = this.text.split('').reverse().join(''); } } ``` ##### preventDefault() ```html <a href="https://www.google.com.tw" v-on:click.prevent="reverseText" target="_blank" >反轉字串</a> ``` ### 修飾符 [Event Handling — Vue.js](https://vuejs.org/v2/guide/events.html) ```html <input type="text" v-model="text" v-on:keyup.enter="reverseText"> ``` ```html <input type="text" v-model="text" @keyup.enter="reverseText"> <button @click.prevent="reverseText">反轉字串</button> ``` ### v-class - :class="{ '要加入的class': 判斷式 }" - 傳入**物件** - 多個class用空白隔開 - 多個判斷式用 ',', 如 { '要加入的class': 判斷式, '要加入的class': 判斷式 } ```html <div class="box" :class="isTransform ? 'rotate':'' "></div> <div class="box" :class="{ 'rotate abc': isTransform }"></div> <div class="box" :class="{ 'rotate': isTransform, 'bg-danger': boxColor}"></div> ``` - 物件寫法 ``` // html :class="objectClass" // js objectClass: { 'rotate': false, 'bg-danger': false, } ``` > 用在不確定要加上幾個className時 - 陣列寫法 ```html <button class="btn" :class="arrayClass">請操作本元件</button> <div class="form-check"> <input type="checkbox" class="form-check-input" id="classToggle3" v-model="arrayClass" value="btn-outline-primary"> <label class="form-check-label" for="classToggle3">切換樣式</label> </div> <div class="form-check"> <input type="checkbox" class="form-check-input" id="classToggle4" v-model="arrayClass" value="active"> <label class="form-check-label" for="classToggle4">啟用元素狀態</label> </div> ``` ### :sytle ```html <div class="box" :style="{'backgroundColor': 'red'}"></div> <div class="box" :style="styleObject"></div> <div class="box" :style="[{'backgroundColor': 'red'}, {'border': '10px solid #ccc'}]"></div> ``` - 陣列中插入object ```html <div class="box" :style="[styleObject, styleObject2]"></div> ``` ```javascript // 使用駝峰式命名 styleObject: { backgroundColor: 'red', borderWidth: '5px' }, styleObject2: { boxShadow: '3px 3px 5px rgba(0, 0, 0, 0.16)' } ``` > Vue在動態加入樣式時,會自動加上Prefix ## key - 由於效能考量,在預設的狀況下,Vue.js 會儘量重覆使用已渲染好的元素。若不設定 key 值,不會重新渲染元素,只會部份更新。 - 綁定一個屬性 :key 並設定唯一值,目的是確保每個元素的唯一性,當元素更新,例如改變順序時,有可識別唯一性的 key 來確保重新渲染。 ```html <li v-for="(item, index) in list" :key="item.id"> {{index}} <input type="text" :placeholder="item.name" /> </li> ``` # 在組件上使用 v-model [說明文](https://cn.vuejs.org/v2/guide/components.html#%E9%80%9A%E8%BF%87-Prop-%E5%90%91%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BC%A0%E9%80%92%E6%95%B0%E6%8D%AE) ```htmlmixed= <input v-model="searchText"> ``` - 等價於 ```htmlmixed= <input v-bind:value="searchText" v-on:input="searchText = $event.target.value" > ``` ### 元件間 v-model 範例 ```htmlmixed= <custom-input v-bind:value="searchText" v-on:input="searchText = $event" ></custom-input> <!-- or --> <custom-input v-model="searchText"></custom-input> ``` ```javascript= Vue.component('custom-input', { props: ['value'], template: ` <input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > ` }) ``` - 客製 v-model [參考說明](https://ithelp.ithome.com.tw/articles/10209183) > v-model預設是用value當作prop,input當event,有時checkbox或radio或將value用在不同用途,因此用 "model" 可避免衝突 ```javascript= Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' }, props: { checked: Boolean }, template: ` <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > ` }) ``` ```htmlmixed= <base-checkbox v-model="lovingVue"></base-checkbox> ```