Vue自定义指令原来这么简单
本篇學(xué)習(xí)目標(biāo)
1. 組件進(jìn)階
1.0 組件進(jìn)階 - 動(dòng)態(tài)組件
目標(biāo): 多個(gè)組件使用同一個(gè)掛載點(diǎn),并動(dòng)態(tài)切換,這就是動(dòng)態(tài)組件
需求: 完成一個(gè)注冊(cè)功能頁面, 2個(gè)按鈕切換, 一個(gè)填寫注冊(cè)信息, 一個(gè)填寫用戶簡(jiǎn)介信息
效果如下:
準(zhǔn)備被切換的 - UserName.vue / UserInfo.vue 2個(gè)組件
引入到UseDynamic.vue注冊(cè)
準(zhǔn)備變量來承載要顯示的"組件名"
設(shè)置掛載點(diǎn), 使用is屬性來設(shè)置要顯示哪個(gè)組件
點(diǎn)擊按鈕 – 修改comName變量里的"組件名"
在App.vue - 引入01_UseDynamic.vue并使用顯示
總結(jié): vue內(nèi)置component組件, 配合is屬性, 設(shè)置要顯示的組件名字
1.1 組件進(jìn)階 - 組件緩存
目標(biāo): 組件切換會(huì)導(dǎo)致組件被頻繁銷毀和重新創(chuàng)建, 性能不高
使用Vue內(nèi)置的keep-alive組件, 可以讓包裹的組件保存在內(nèi)存中不被銷毀
演示1: 可以先給UserName.vue和UserInfo.vue 注冊(cè)created和destroyed生命周期事件, 觀察創(chuàng)建和銷毀過程
演示2: 使用keep-alive內(nèi)置的vue組件, 讓動(dòng)態(tài)組件緩存而不是銷毀
語法:
? Vue內(nèi)置的keep-alive組件 包起來要頻繁切換的組件
02_UseDynamic.vue
<div style="border: 1px solid red;"><!-- Vue內(nèi)置keep-alive組件, 把包起來的組件緩存起來 --><keep-alive><component :is="comName"></component></keep-alive> </div>補(bǔ)充生命周期:
- activated - 激活
- deactivated - 失去激活狀態(tài)
總結(jié): keep-alive可以提高組件的性能, 內(nèi)部包裹的標(biāo)簽不會(huì)被銷毀和重新創(chuàng)建, 觸發(fā)激活和非激活的生命周期方法
1.2 組件進(jìn)階 - 激活和非激活
目標(biāo): 被緩存的組件不再創(chuàng)建和銷毀, 而是激活和非激活
補(bǔ)充2個(gè)鉤子方法名:
? activated – 激活時(shí)觸發(fā)
? deactivated – 失去激活狀態(tài)觸發(fā)
1.3 組件進(jìn)階 - 組件插槽
目標(biāo): 用于實(shí)現(xiàn)組件的內(nèi)容分發(fā), 通過 slot 標(biāo)簽, 可以接收到寫在組件標(biāo)簽內(nèi)的內(nèi)容
vue提供組件插槽能力, 允許開發(fā)者在封裝組件時(shí),把不確定的部分定義為插槽
插槽例子:
需求: 以前折疊面板案例, 想要實(shí)現(xiàn)不同內(nèi)容顯示, 我們把折疊面板里的Pannel組件, 添加組件插槽方式
語法口訣:
03/Pannel.vue - 組件(直接復(fù)制)
<template><div><!-- 按鈕標(biāo)題 --><div class="title"><h4>芙蓉樓送辛漸</h4><span class="btn" @click="isShow = !isShow">{{ isShow ? "收起" : "展開" }}</span></div><!-- 下拉內(nèi)容 --><div class="container" v-show="isShow"><p>寒雨連江夜入?yún)?</p><p>平明送客楚山孤。</p><p>洛陽親友如相問,</p><p>一片冰心在玉壺。</p></div></div> </template><script> export default {data() {return {isShow: false,};}, }; </script><style scoped> h3 {text-align: center; }.title {display: flex;justify-content: space-between;align-items: center;border: 1px solid #ccc;padding: 0 1em; }.title h4 {line-height: 2;margin: 0; }.container {border: 1px solid #ccc;padding: 0 1em; }.btn {/* 鼠標(biāo)改成手的形狀 */cursor: pointer; }img {width: 50%; } </style>views/03_UserSlot.vue - 使用組件(直接復(fù)制)
框: 在這個(gè)基礎(chǔ)重復(fù)使用組件
<template><div id="container"><div id="app"><h3>案例:折疊面板</h3></div></div> </template><script> export default { }; </script><style> #app {width: 400px;margin: 20px auto;background-color: #fff;border: 4px solid blueviolet;border-radius: 1em;box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.5);padding: 1em 2em 2em; } </style>views/03_UseSlot.vue - 組件插槽使用
<template><div id="container"><div id="app"><h3>案例:折疊面板</h3><Pannel><img src="../assets/mm.gif" alt=""><span>我是內(nèi)容</span></Pannel><Pannel><p>寒雨連江夜入?yún)?</p><p>平明送客楚山孤。</p><p>洛陽親友如相問,</p><p>一片冰心在玉壺。</p></Pannel><Pannel></Pannel></div></div> </template><script> import Pannel from "../components/03/Pannel"; export default {components: {Pannel,}, }; </script>總結(jié): 組件內(nèi)容分發(fā)技術(shù), slot占位, 使用組件時(shí)傳入替換slot位置的標(biāo)簽
1.4 組件進(jìn)階 - 插槽默認(rèn)內(nèi)容
目標(biāo): 如果外面不給傳, 想給個(gè)默認(rèn)顯示內(nèi)容
口訣: 夾著內(nèi)容默認(rèn)顯示內(nèi)容, 如果不給插槽slot傳東西, 則使用夾著的內(nèi)容在原地顯示
<slot>默認(rèn)內(nèi)容</slot>1.5 組件進(jìn)階 - 具名插槽
目標(biāo): 當(dāng)一個(gè)組件內(nèi)有2處以上需要外部傳入標(biāo)簽的地方
傳入的標(biāo)簽可以分別派發(fā)給不同的slot位置
要求: v-slot一般用跟template標(biāo)簽使用 (template是html5新出標(biāo)簽內(nèi)容模板元素, 不會(huì)渲染到頁面上, 一般被vue解析內(nèi)部標(biāo)簽)
components/04/Pannel.vue - 留下具名slot
<template><div><!-- 按鈕標(biāo)題 --><div class="title"><slot name="title"></slot><span class="btn" @click="isShow = !isShow">{{ isShow ? "收起" : "展開" }}</span></div><!-- 下拉內(nèi)容 --><div class="container" v-show="isShow"><slot name="content"></slot></div></div> </template>views/04_UseSlot.vue使用
<template><div id="container"><div id="app"><h3>案例:折疊面板</h3><Pannel><template v-slot:title><h4>芙蓉樓送辛漸</h4></template><template v-slot:content><img src="../assets/mm.gif" alt=""><span>我是內(nèi)容</span></template></Pannel><Pannel><template #title><span style="color: red;">我是標(biāo)題</span></template><template #content><p>寒雨連江夜入?yún)?</p><p>平明送客楚山孤。</p><p>洛陽親友如相問,</p><p>一片冰心在玉壺。</p></template></Pannel></div></div> </template><script> import Pannel from "../components/04/Pannel"; export default {components: {Pannel,}, }; </script>v-slot可以簡(jiǎn)化成#使用
v-bind可以省略成: v-on: 可以省略成@ 那么v-slot: 可以簡(jiǎn)化成#
總結(jié): slot的name屬性起插槽名, 使用組件時(shí), template配合#插槽名傳入具體標(biāo)簽
1.6 組件進(jìn)階 - 作用域插槽
目標(biāo): 子組件里值, 在給插槽賦值時(shí)在父組件環(huán)境下使用
復(fù)習(xí): 插槽內(nèi)slot中顯示默認(rèn)內(nèi)容
例子: 默認(rèn)內(nèi)容在子組件中, 但是父親在給插槽傳值, 想要改變插槽顯示的默認(rèn)內(nèi)容
口訣:
components/05/Pannel.vue - 定義組件, 和具名插槽, 給slot綁定屬性和值
<template><div><!-- 按鈕標(biāo)題 --><div class="title"><h4>芙蓉樓送辛漸</h4><span class="btn" @click="isShow = !isShow">{{ isShow ? "收起" : "展開" }}</span></div><!-- 下拉內(nèi)容 --><div class="container" v-show="isShow"><slot :row="defaultObj">{{ defaultObj.defaultOne }}</slot></div></div> </template><script> // 目標(biāo): 作用域插槽 // 場(chǎng)景: 使用插槽, 使用組件內(nèi)的變量 // 1. slot標(biāo)簽, 自定義屬性和內(nèi)變量關(guān)聯(lián) // 2. 使用組件, template配合v-slot="變量名" // 變量名會(huì)收集slot身上屬性和值形成對(duì)象 export default {data() {return {isShow: false,defaultObj: {defaultOne: "無名氏",defaultTwo: "小傳同學(xué)"}};}, }; </script>views/05_UseSlot.vue
<template><div id="container"><div id="app"><h3>案例:折疊面板</h3><Pannel><!-- 需求: 插槽時(shí), 使用組件內(nèi)變量 --><!-- scope變量: {row: defaultObj} --><template v-slot="scope"><p>{{ scope.row.defaultTwo }}</p></template></Pannel></div></div> </template><script> import Pannel from "../components/05/Pannel"; export default {components: {Pannel,}, }; </script>總結(jié): 組件內(nèi)變量綁定在slot上, 然后使用組件v-slot=“變量” 變量上就會(huì)綁定slot身上屬性和值
1.7 組件進(jìn)階 - 作用域插槽使用場(chǎng)景
目標(biāo): 了解作用域插槽使用場(chǎng)景, 自定義組件內(nèi)標(biāo)簽+內(nèi)容
案例: 封裝一個(gè)表格組件, 在表格組件內(nèi)循環(huán)產(chǎn)生單元格
準(zhǔn)備MyTable.vue組件 – 內(nèi)置表格, 傳入數(shù)組循環(huán)鋪設(shè)頁面, 把對(duì)象每個(gè)內(nèi)容顯示在單元格里
準(zhǔn)備UseTable.vue – 準(zhǔn)備數(shù)據(jù)傳入給MyTable.vue使用
components/06/MyTable.vue - 模板(直接復(fù)制)
<template><div><table border="1"><thead><tr><th>序號(hào)</th><th>姓名</th><th>年齡</th><th>頭像</th></tr></thead><thead><tr><td></td><td></td><td></td><td></td></tr></thead></table></div> </template><script> export default {} </script>views/06_UseTable.vue - 準(zhǔn)備數(shù)據(jù), 傳入給MyTable.vue組件里循環(huán)使用
list: [{name: "小傳同學(xué)",age: 18,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",},{name: "小黑同學(xué)",age: 25,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",},{name: "智慧同學(xué)",age: 21,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",}, ],例子: 我想要給td內(nèi)顯示圖片, 需要傳入自定義的img標(biāo)簽
正確做法:
? 在MyTable.vue的td中準(zhǔn)備占位, 但是外面需要把圖片地址賦予給src屬性,所以在slot上把obj數(shù)據(jù)綁定
components/06/MyTable.vue - 正確代碼
<template><div><table border="1"><thead><tr><th>序號(hào)</th><th>姓名</th><th>年齡</th><th>頭像</th></tr></thead><tbody><tr v-for="(obj, index) in arr" :key="index"><td>{{ index + 1 }}</td><td>{{ obj.name }}</td><td>{{ obj.age }}</td><td><slot :row="obj"><!-- 默認(rèn)值給上,如果使用組件不自定義標(biāo)簽顯示默認(rèn)文字 -->{{ obj.headImgUrl}}</slot></td></tr></tbody></table></div> </template><script> export default {props: {arr: Array} } </script>? 在UseTable使用MyTable的時(shí)候, template上v-slot綁定變量, 傳入img組件設(shè)置圖片地址
<template><div><MyTable :arr="list"></MyTable><MyTable :arr="list"><!-- scope: {row: obj} --><template v-slot="scope"><a :href="scope.row.headImgUrl">{{ scope.row.headImgUrl }}</a></template></MyTable><MyTable :arr="list"><template v-slot="scope"><img style="width: 100px;" :src="scope.row.headImgUrl" alt=""></template></MyTable></div> </template><script> import MyTable from "../components/06/MyTable"; export default {components: {MyTable,},data() {return {list: [{name: "小傳同學(xué)",age: 18,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",},{name: "小黑同學(xué)",age: 25,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",},{name: "智慧同學(xué)",age: 21,headImgUrl:"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",},],};}, }; </script><style> </style>總結(jié): 插槽可以自定義標(biāo)簽, 作用域插槽可以把組件內(nèi)的值取出來自定義內(nèi)容
2. 自定義指令
自定義指令文檔
除了核心功能默認(rèn)內(nèi)置的指令 (v-model 和 v-show),Vue 也允許注冊(cè)自定義指令。 v-xxx
html+css的復(fù)用的主要形式是組件
你需要對(duì)普通 DOM 元素進(jìn)行底層操作,這時(shí)候就會(huì)用到自定義指令
2.0 自定義指令-注冊(cè)
目標(biāo): 獲取標(biāo)簽, 擴(kuò)展額外的功能
局部注冊(cè)和使用
07_UseDirective.vue - 只能在當(dāng)前組件.vue文件中使用
<template><div><!-- <input type="text" v-gfocus> --><input type="text" v-focus></div> </template><script> // 目標(biāo): 創(chuàng)建 "自定義指令", 讓輸入框自動(dòng)聚焦 // 1. 創(chuàng)建自定義指令 // 全局 / 局部 // 2. 在標(biāo)簽上使用自定義指令 v-指令名 // 注意: // inserted方法 - 指令所在標(biāo)簽, 被插入到網(wǎng)頁上觸發(fā)(一次) // update方法 - 指令對(duì)應(yīng)數(shù)據(jù)/標(biāo)簽更新時(shí), 此方法執(zhí)行 export default {data(){return {colorStr: 'red'}},directives: {focus: {inserted(el){el.focus()}}} } </script><style></style>全局注冊(cè)
在main.js用 Vue.directive()方法來進(jìn)行注冊(cè), 以后隨便哪個(gè).vue文件里都可以直接用v-fofo指令
// 全局指令 - 到處"直接"使用 Vue.directive("gfocus", {inserted(el) {el.focus() // 觸發(fā)標(biāo)簽的事件方法} })總結(jié): 全局注冊(cè)自定義指令, 哪里都能用, 局部注冊(cè), 只能在當(dāng)前vue文件里用
2.1 自定義指令-傳值
目標(biāo): 使用自定義指令, 傳入一個(gè)值
需求: 定義color指令-傳入一個(gè)顏色, 給標(biāo)簽設(shè)置文字顏色
main.js定義處修改一下
// 目標(biāo): 自定義指令傳值 Vue.directive('color', {inserted(el, binding) {el.style.color = binding.value},update(el, binding) {el.style.color = binding.value} })Direct.vue處更改一下
<p v-color="colorStr" @click="changeColor">修改文字顏色</p><script>data() {return {theColor: "red",};},methods: {changeColor() {this.theColor = 'blue';},}, </script>總結(jié): v-xxx, 自定義指令, 獲取原生DOM, 自定義操作
3. 案例-tabbar
完成如下案例和各步功能
知識(shí)點(diǎn):
- 組件封裝
- 動(dòng)態(tài)組件
- keep-alive
- 作用域插槽
- 自定義指令
3.0 案例-tabbar-初始化項(xiàng)目
目標(biāo): 創(chuàng)建項(xiàng)目文件夾, 引入字體圖標(biāo), 下載bootstrap, less, less-loader@5.0.0 axios, 在App.vue注冊(cè)組件
- 需求: 從0新建項(xiàng)目, 拆分組件, 創(chuàng)建使用
組件分析:
-
組件拆分:
- MyHeader.vue – 復(fù)用之前的
- MyTabBar.vue – 底部導(dǎo)航
- MyTable.vue – 封裝表格
-
三個(gè)頁面
- -MyGoodsList.vue – 商品頁
- MyGoodsSearch.vue – 搜索頁
- -MyUserInfo.vue – 用戶信息頁
思路分析:
? ①: vue create tabbar-demo
? ②: yarn add less less-loader@5.0.0 -D
? ③: yarn add bootstrap axios 并在main.js 引入和全局屬性
? ④: 根據(jù)需求-創(chuàng)建需要的頁面組件
? ⑤: 把昨天購物車案例-封裝的MyHeader.vue文件復(fù)制過來復(fù)用
? ⑥: 從App.vue – 引入組織相關(guān)標(biāo)簽
新建工程:
vue create tabbar-demo yarn add less less-loader@5.0.0 -D yarn add bootstrap axios在main.js中引入bootStrap.css和字體圖標(biāo)樣式
import "bootstrap/dist/css/bootstrap.css" import "./assets/fonts/iconfont.css"創(chuàng)建/復(fù)制如下文件
從昨天案例中-直接復(fù)制過來components/MyHeader.vue
components/MyTabBar.vue
views/MyGoodsList.vue
views/MyGoodsSearch.vue
views/MyUserInfo.vue
components/MyTable.vue
3.1 案例-tabbar-底部封裝
目標(biāo): 實(shí)現(xiàn)MyTabBar.vue組件
- 需求: 把底部導(dǎo)航也靈活封裝起來
分析:
? ①: 基本標(biāo)簽+樣式(md里復(fù)制)
? ②: 為tabbar組件指定數(shù)據(jù)源
? ③: 數(shù)據(jù)源最少2個(gè), 最多5個(gè)(validator)
? ④: 從App.vue給MyTabBar.vue傳入底部導(dǎo)航的數(shù)據(jù)
? ⑤: MyTabBar.vue中循環(huán)展示
App.vue-數(shù)組準(zhǔn)備
tabList: [{iconText: "icon-shangpinliebiao",text: "商品列表",componentName: "MyGoodsList"},{iconText: "icon-sousuo",text: "商品搜索",componentName: "MyGoodsSearch"},{iconText: "icon-user",text: "我的信息",componentName: "MyUserInfo"} ]MyTabBar.vue - 標(biāo)簽?zāi)0?/p> <template><div class="my-tab-bar"><div class="tab-item"><!-- 圖標(biāo) --><span class="iconfont"></span><!-- 文字 --><span></span></div></div> </template><script> export default {} </script><style lang="less" scoped> .my-tab-bar {position: fixed;left: 0;bottom: 0;width: 100%;height: 50px;border-top: 1px solid #ccc;display: flex;justify-content: space-around;align-items: center;background-color: white;.tab-item {display: flex;flex-direction: column;align-items: center;} }.current {color: #1d7bff; } </style>
MyTabBar.vue正確代碼(不可復(fù)制)
<template><div class="my-tab-bar"><divclass="tab-item"v-for="(obj, index) in arr":key="index"><!-- 圖標(biāo) --><span class="iconfont" :class="obj.iconText"></span><!-- 文字 --><span>{{ obj.text }}</span></div></div> </template><script> export default {props: {arr: {type: Array,required: true,// 自定義校驗(yàn)規(guī)則validator(value) {// value就是接到數(shù)組if (value.length >= 2 && value.length <= 5) {return true; // 符合條件就return true} else {console.error("數(shù)據(jù)源必須在2-5項(xiàng)");return false;}},},} }; </script>不要忘了把tabList數(shù)組從App.vue -> MyTabBar.vue
3.2 案例-tabbar-底部高亮
目標(biāo): 點(diǎn)擊底部導(dǎo)航實(shí)現(xiàn)高亮效果
- 需求: 點(diǎn)擊底部實(shí)現(xiàn)高亮效果
分析:
? ①: 綁定點(diǎn)擊事件, 獲取點(diǎn)擊的索引
? ②: 循環(huán)的標(biāo)簽設(shè)置動(dòng)態(tài)class, 遍歷的索引, 和點(diǎn)擊保存的索引比較, 相同則高亮
效果演示:
MyTabBar.vue(正確代碼)
<template><div class="my-tab-bar"><div class="tab-item" v-for="(obj, index) in arr" :key="index":class="{current: activeIndex === index}"@click="activeIndex = index"><!-- 圖標(biāo) --><span class="iconfont" :class="obj.iconText"></span><!-- 文字 --><span>{{ obj.text }}</span></div></div> </template><script> export default {data(){return {activeIndex: 0 // 高亮元素下標(biāo)}},// ....其他代碼 }; </script>3.3 案例-tabbar-組件切換
目的: 點(diǎn)擊底部導(dǎo)航, 切換頁面組件顯示
需求: 點(diǎn)擊底部切換組件
分析:
? ①: 底部導(dǎo)航傳出動(dòng)態(tài)組件名字符串到App.vue
? ②: 切換動(dòng)態(tài)組件is屬性的值為要顯示的組件名
效果演示:
補(bǔ)充: 給內(nèi)容div.app- 設(shè)置上下內(nèi)邊距
App.vue - 引入并注冊(cè)
<template><div><MyHeader:background="'blue'":fontColor="'white'"title="TabBar案例"></MyHeader><div class="main"><component :is="comName"></component></div><MyTabBar :arr="tabList"@changeCom="changeComFn"></MyTabBar></div> </template><script> import MyHeader from "./components/MyHeader"; // 目標(biāo): 完成底部封裝 // 1. MyTabBar.vue 組件標(biāo)簽+樣式 準(zhǔn)備 // 2. 字體圖標(biāo)引入 // 3. 準(zhǔn)備底部數(shù)據(jù) // 4. 使用MyTabBar組件, 傳入數(shù)據(jù)(父->子), 循環(huán)產(chǎn)生底部導(dǎo)航 // 5. 子組件內(nèi)props自定義檢驗(yàn)規(guī)則(2-5項(xiàng)) // 6. 子組件內(nèi)循環(huán)產(chǎn)生底部導(dǎo)航 import MyTabBar from './components/MyTabBar'// 目標(biāo): 切換組件顯示 // 1. 創(chuàng)建組件 - 編寫內(nèi)容 // 2. 引入App.vue注冊(cè) // 3. 掛載點(diǎn)設(shè)置is // 4. 切換comName的值(重要) // 5. 底部導(dǎo)航點(diǎn)擊- MyTabBar.vue里 // 子 -> 父技術(shù) (傳要切換的組件名出來)import MyGoodsList from './views/MyGoodsList' import MyGoodsSearch from './views/MyGoodsSearch' import MyUserInfo from './views/MyUserInfo' export default {data() {return {comName: "MyGoodsList", // 默認(rèn)顯示的組件tabList: [ // 底部導(dǎo)航的數(shù)據(jù){iconText: "icon-shangpinliebiao",text: "商品列表",componentName: "MyGoodsList",},{iconText: "icon-sousuo",text: "商品搜索",componentName: "MyGoodsSearch",},{iconText: "icon-user",text: "我的信息",componentName: "MyUserInfo",},],};},components: {MyHeader,MyTabBar,MyGoodsList,MyGoodsSearch,MyUserInfo},methods: {changeComFn(cName){this.comName = cName; // MyTabBar里選出來的組件名賦予給is屬性的comName// 導(dǎo)致組件的切換}} }; </script><style scoped> .main{padding-top: 45px;padding-bottom: 51px; } </style>MyTabBar.vue - 點(diǎn)擊傳遞過來組件名
methods: {btn(index, theObj) {this.selIndex = index; // 點(diǎn)誰, 就把誰的索引值保存起來this.$emit("changeCom", theObj.componentName); // 要切換的組件名傳App.vue},},3.4 案例-tabbar-商品列表
目標(biāo): 為MyGoodsList頁面, 準(zhǔn)備表格組件MyTable.vue-鋪設(shè)展示數(shù)據(jù)
- 需求: 商品列表鋪設(shè)頁面
分析:
? ①: 封裝MyTable.vue – 準(zhǔn)備標(biāo)簽和樣式
? ②: axios在MyGoodsList.vue請(qǐng)求數(shù)據(jù)回來
? ③: 請(qǐng)求地址: https://www.escook.cn/api/goods
? ④: 傳入MyTable.vue中循環(huán)數(shù)據(jù)顯示
? ⑤: 給刪除按鈕添加bootstrap的樣式: btn btn-danger btn-sm
效果演示:
MyTable.vue - 準(zhǔn)備table整個(gè)表格標(biāo)簽和樣式(可復(fù)制)
<template><table class="table table-bordered table-stripped"><!-- 表格標(biāo)題區(qū)域 --><thead><tr><th>#</th><th>商品名稱</th><th>價(jià)格</th><th>標(biāo)簽</th><th>操作</th></tr></thead><!-- 表格主體區(qū)域 --><tbody><tr ><td>1</td><td>商品</td><td>998</td><td>xxx</td><td>xxx</td></tr></tbody></table> </template><script> export default {name: 'MyTable' } </script><style scoped lang="less"> .my-goods-list {.badge {margin-right: 5px;} } </style>使用axios請(qǐng)求數(shù)據(jù), 把表格頁面鋪設(shè)出來
main.js - 注冊(cè)axios配置默認(rèn)地址
import axios from "axios"; axios.defaults.baseURL = "https://www.escook.cn";MyGoodsList.vue - 使用axios請(qǐng)求數(shù)據(jù), 把數(shù)據(jù)傳入給MyTable.vue里循環(huán)鋪設(shè)
<template><div><MyTable :arr="list"></MyTable></div> </template><script> import MyTable from "../components/MyTable"; import axios from "axios"; axios.defaults.baseURL = "https://www.escook.cn"; // 目標(biāo): 循環(huán)商品列表表格 // 1. 封裝MyTable.vue 整體表格組件-一套標(biāo)簽和樣式 // 2. axios請(qǐng)求數(shù)據(jù) // 3. 傳入MyTable組件里循環(huán)tr顯示數(shù)據(jù)// 目標(biāo): 展示tags標(biāo)簽 // 1. tags數(shù)組 - 某個(gè)td循環(huán)span使用文字 // 2. span設(shè)置bs的樣式// 目標(biāo): 刪除數(shù)據(jù) // 1. 刪除按鈕 - 點(diǎn)擊事件 // 2. 作用域插槽把索引值關(guān)聯(lián)出來了 // scope身上就有row和index // 3. 刪除中使用scope.index的索引值 // 4. 刪除事件里刪除數(shù)組里對(duì)應(yīng)索引值的數(shù)據(jù) export default {components: {MyTable,},data() {return {list: [] // 所有數(shù)據(jù)};},created() {axios({url: "/api/goods",}).then((res) => {console.log(res);this.list = res.data.data;});} }; </script>MyTable.vue里正確代碼(不可復(fù)制)
<template><table class="table table-bordered table-stripped"><!-- 表格標(biāo)題區(qū)域 --><thead><tr><th>#</th><th>商品名稱</th><th>價(jià)格</th><th>標(biāo)簽</th><th>操作</th></tr></thead><!-- 表格主體區(qū)域 --><tbody><tr v-for="(obj, index) in arr":key="obj.id"><td>{{ obj.id }}</td><td>{{ obj.goods_name }}</td><td>{{ obj.goods_price }}</td><td>{{ obj.tags }}</td><td><button class="btn btn-danger btn-sm">刪除</button></td></tr></tbody></table> </template><script> export default {name: 'MyTable',props: {arr: Array} } </script><style scoped lang="less"> .my-goods-list {.badge {margin-right: 5px;} } </style>3.5_案例-tabbar-商品表格-插槽
目標(biāo): 使用插槽技術(shù), 和作用域插槽技術(shù), 給MyTable.vue組件, 自定義列標(biāo)題, 自定義表格內(nèi)容
- 需求: 允許用戶自定義表格頭和表格單元格內(nèi)容
分析:
? ①: 把MyTable.vue里準(zhǔn)備slot
? ②: 使用MyTable組件時(shí)傳入具體標(biāo)簽
步驟:
MyTable.vue - 留好具名插槽
<template><table class="table table-bordered table-stripped"><!-- 表格標(biāo)題區(qū)域 --><thead><tr><!-- <th>#</th><th>商品名稱</th><th>價(jià)格</th><th>標(biāo)簽</th><th>操作</th> --><slot name="header"></slot></tr></thead><!-- 表格主體區(qū)域 --><tbody><tr v-for="(obj, index) in arr":key="obj.id"><!-- <td>{{ obj.id }}</td><td>{{ obj.goods_name }}</td><td>{{ obj.goods_price }}</td><td>{{ obj.tags }}</td><td><button class="btn btn-danger btn-sm">刪除</button></td> --><slot name="body" :row="obj" :index="index"></slot></tr></tbody></table> </template><script> export default {name: 'MyTable',props: {arr: Array} } </script>MyGoodsList.vue 使用
<template><div><MyTable :arr="list"><template #header><th>#</th><th>商品名稱</th><th>價(jià)格</th><th>標(biāo)簽</th><th>操作</th></template><!-- scope的值: {row: obj, index: 索引值} --><template #body="scope"><td>{{ scope.row.id }}</td><td>{{ scope.row.goods_name }}</td><td>{{ scope.row.goods_price }}</td><td>{{ scope.row.tags }}</td><td><button class="btn btn-danger btn-sm">刪除</button></td></template></MyTable></div> </template><script> import MyTable from "../components/MyTable"; import axios from "axios"; axios.defaults.baseURL = "https://www.escook.cn"; // 目標(biāo): 循環(huán)商品列表表格 // 1. 封裝MyTable.vue 整體表格組件-一套標(biāo)簽和樣式 // 2. axios請(qǐng)求數(shù)據(jù) // 3. 傳入MyTable組件里循環(huán)tr顯示數(shù)據(jù)// 目標(biāo): 展示tags標(biāo)簽 // 1. tags數(shù)組 - 某個(gè)td循環(huán)span使用文字 // 2. span設(shè)置bs的樣式// 目標(biāo): 刪除數(shù)據(jù) // 1. 刪除按鈕 - 點(diǎn)擊事件 // 2. 作用域插槽把索引值關(guān)聯(lián)出來了 // scope身上就有row和index // 3. 刪除中使用scope.index的索引值 // 4. 刪除事件里刪除數(shù)組里對(duì)應(yīng)索引值的數(shù)據(jù) export default {components: {MyTable,},data() {return {list: [] // 所有數(shù)據(jù)};},created() {axios({url: "/api/goods",}).then((res) => {console.log(res);this.list = res.data.data;});} }; </script><style> </style>3.6 案例-tabbar-商品表格-tags微標(biāo)
目標(biāo): 把單元格里的標(biāo)簽, tags徽章鋪設(shè)下
- 需求: 標(biāo)簽列自定義顯示
分析:
? ①: 插槽里傳入的td單元格
? ②: 自定義span標(biāo)簽的循環(huán)展示-給予樣式
效果演示:
bootstrap徽章: https://v4.bootcss.com/docs/components/badge/
MyGoodsList.vue - 插槽
<span v-for="(str, ind) in scope.row.tags" :key="ind"class="badge badge-warning">{{ str }} </span>下面額外添加樣式
<style lang="less" scoped> .my-goods-list {.badge {margin-right: 5px;} } </style>3.7 案例-tabbar-商品表格-刪除功能
目標(biāo): 點(diǎn)擊刪除對(duì)應(yīng)這條數(shù)據(jù)
- 需求: 點(diǎn)擊刪除按鈕刪除數(shù)據(jù)
分析:
? ①: 刪除按鈕綁定點(diǎn)擊事件
? ②: 作用域插槽綁定id值出來
? ③: 傳給刪除方法, 刪除MyGoodsList.vue里數(shù)組里數(shù)據(jù)
效果演示
提示: id在MyTable.vue里, 但是MyGoodsList.vue里要使用, 而且在插槽位置, 使用作用域插槽已經(jīng)把整個(gè)obj對(duì)象(包含id)帶出來了
MyTable.vue
<slot name="body" :row="obj"></slot>? 2. my-goods-list.vue 根據(jù) id 刪除
removeBtn(id){let index = this.list.findIndex(obj => obj.id === id)this.list.splice(index, 1) },3.8 案例-tabbar-添加tab
目標(biāo): 實(shí)現(xiàn)點(diǎn)擊tab按鈕, 出現(xiàn)輸入框自動(dòng)獲取焦點(diǎn), 失去焦點(diǎn)關(guān)閉input, 回車新增tag, esc清空內(nèi)容
- 需求1: 點(diǎn)擊Tab, 按鈕消失, 輸入框出現(xiàn)
- 需求2: 輸入框自動(dòng)聚焦
- 需求3: 失去焦點(diǎn), 輸入框消失, 按鈕出
- 需求4: 監(jiān)測(cè)input回車, 無數(shù)據(jù)攔截
- 需求5: 監(jiān)測(cè)input取消, 清空數(shù)據(jù)
- 需求6: 監(jiān)測(cè)input回車, 有數(shù)據(jù)添加
效果目標(biāo):
3.8.0 點(diǎn)擊按鈕消失, 輸入框出現(xiàn)
MyGoodsList.vue - 標(biāo)簽位置添加
注意: 每個(gè)tab按鈕和input都是獨(dú)立變量控制, 那么直接在row身上的屬性控制即可
<inputclass="tag-input form-control"style="width: 100px;"type="text"v-if="scope.row.inputVisible"/><button v-else style="display: block;" class="btn btn-primary btn-sm add-tag"@click="scope.row.inputVisible = true">+Tag</button>3.8.1 input自動(dòng)獲取焦點(diǎn)
main.js - 定義全局自定義指令
// 全局指令 Vue.directive("focus", {inserted(el){el.focus()} })MyGoodsList.vue - 使用 v-focus指令
3.8.2 input失去焦點(diǎn)關(guān)閉input
監(jiān)聽input失去焦點(diǎn)事件, 讓input消失
@blur="scope.row.inputVisible = false"3.8.3 input回車新增tag
監(jiān)聽input的回車事件, 如果無數(shù)據(jù)攔截代碼
@keydown.enter="enterFn(scope.row)"事件處理函數(shù)
enterFn(obj){ // 回車// console.log(obj.inputValue);if (obj.inputValue.trim().length === 0) {alert('請(qǐng)輸入數(shù)據(jù)')return}obj.tags.push(obj.inputValue) // 表單里的字符串狀態(tài)tags數(shù)組obj.inputValue = "" }3.8.4 input框esc清空內(nèi)容
@keydown.esc="scope.row.inputValue = ''"今日總結(jié)
面試題
1. vue中solt的使用方式,以及solt作用域插槽的用法
使用方式:當(dāng)組件當(dāng)做標(biāo)簽進(jìn)行使用的時(shí)候,用slot可以用來接受組件標(biāo)簽包裹的內(nèi)容,當(dāng)給solt標(biāo)簽添加name屬性的 時(shí)候,可以調(diào)換響應(yīng)的位置
(高級(jí)用法) 插槽作用域: 當(dāng)傳遞的不是單一的標(biāo)簽, 例如需要循環(huán)時(shí), 把要循環(huán)的標(biāo)簽傳入, 組件內(nèi)使用v-for在slot標(biāo)簽上, 內(nèi)部可以v-bind:把值傳出來, 再外面把值賦予進(jìn)去, 看示例
擴(kuò)展閱讀: https://cn.vuejs.org/v2/guide/components-slots.html (了解即可, 一般用不上)
2. 跟keep-alive有關(guān)的生命周期是哪些?(必會(huì))
? 1**)前言:**在開發(fā)Vue項(xiàng)目的時(shí)候,大部分組件是沒必要多次渲染的,所以Vue提供了一個(gè)內(nèi)置組件keep-alive來緩存組件內(nèi)部狀態(tài),避免重新渲染,在開發(fā)Vue項(xiàng)目的時(shí)候,大部分組件是沒必要多次渲染的,所以Vue提供了一個(gè)內(nèi)置組件keep-alive來緩存組件內(nèi)部狀態(tài),避免重新渲染
? 2**)生命周期函數(shù):**在被keep-alive包含的組件/路由中,會(huì)多出兩個(gè)生命周期的鉤子:activated 與 deactivated。
? 1**、activated鉤子:**在在組件第一次渲染時(shí)會(huì)被調(diào)用,之后在每次緩存組件被激活時(shí)調(diào)用。
? 2**、Activated鉤子調(diào)用時(shí)機(jī):** 第一次進(jìn)入緩存路由/組件,在mounted后面,beforeRouteEnter守衛(wèi)傳給 next 的回調(diào)函數(shù)之前調(diào)用,并且給因?yàn)榻M件被緩存了,再次進(jìn)入緩存路由、組件時(shí),不會(huì)觸發(fā)這些鉤子函數(shù),beforeCreate created beforeMount mounted 都不會(huì)觸發(fā)
? 1**、deactivated鉤子:**組件被停用(離開路由)時(shí)調(diào)用。
? 2**、deactivated鉤子調(diào)用時(shí)機(jī)**:使用keep-alive就不會(huì)調(diào)用beforeDestroy(組件銷毀前鉤子)和destroyed(組件銷毀),因?yàn)榻M件沒被銷毀,被緩存起來了,這個(gè)鉤子可以看作beforeDestroy的替代,如果你緩存了組件,要在組件銷毀的的時(shí)候做一些事情,可以放在這個(gè)鉤子里,組件內(nèi)的離開當(dāng)前路由鉤子beforeRouteLeave => 路由前置守衛(wèi) beforeEach =>全局后置鉤子afterEach => deactivated 離開緩存組件 => activated 進(jìn)入緩存組件(如果你進(jìn)入的也是緩存路由)
3. 自定義指令(v-check、v-focus)的方法有哪些?它有哪些鉤子函數(shù)?還有哪些鉤子函數(shù)參數(shù)?(必會(huì))
? 全局定義指令:在vue對(duì)象的directive方法里面有兩個(gè)參數(shù),一個(gè)是指令名稱,另外一個(gè)是函數(shù)。組件內(nèi)定義指令:directives
? 鉤子函數(shù):bind(綁定事件觸發(fā))、inserted(節(jié)點(diǎn)插入的時(shí)候觸發(fā))、update(組件內(nèi)相關(guān)更新)
? 鉤子函數(shù)參數(shù):el、binding
4. is這個(gè)特性你有用過嗎?主要用在哪些方面?(高薪常問)
? 1**)動(dòng)態(tài)組件**
? , componentName可以是在本頁面已經(jīng)注冊(cè)的局部組件名和全局組件名,也可以是一個(gè)組件的選項(xiàng)對(duì)象。 當(dāng)控制componentName改變時(shí)就可以動(dòng)態(tài)切換選擇組件。
? 2**)is的用法**
? 有些HTML元素,諸如 <ul>、<ol>、<table>和<select>,對(duì)于哪些元素可以出現(xiàn)在其內(nèi)部是有嚴(yán)格限制的。? 而有些HTML元素,諸如 <li>、<tr> 和 <option>,只能出現(xiàn)在其它某些特定的元素內(nèi)部。 ? <ul>? <card-list></card-list>? </ul>? 所以上面會(huì)被作為無效的內(nèi)容提升到外部,并導(dǎo)致最終渲染結(jié)果出錯(cuò)。應(yīng)該這么寫:
? <ul>? <li is="cardList"></li>? </ul>總結(jié)
以上是生活随笔為你收集整理的Vue自定义指令原来这么简单的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魅族免费换电池第二批焕新机型名单公布:魅
- 下一篇: 一文带你吃透Vue生命周期(结合案例通俗