Attribute 綁定
v-bind:取值方式
開發前準備
安裝node.js需要高于15.0
創建vue項目
npm init vue@latest
安裝
npm install
啟動
npm run dev
模板語法
文本插值 {{ 變量 }}
<p> {{ mesg }} </p>
這種方式公支持單一表達式,也可以是js代碼,但是這代碼需要有返回值
原始html格式 v-html
<p v-html="屬性鍵"></p>
這個可以實現將返回的屬性鍵值是 html 的格式下,正確解析出 html
如 鍵為 baidu:<a href='http://www.baidu.com'>百度</a>
剛腳本內寫成
<p v-html="baidu"></p>
屬性綁定
v-bind:屬性名
簡寫方式為 :屬性名,如 v-bind:id,等同于:id
雙大括號不能在 html 標簽的屬性中使用,如果要響應式綁定,需要使用v-bind指令
即實現動態屬性值
<script >export default{data(){return {dtclass:"active",dtid:"dtid"}}}
</script><template><div v-bind:id="dtid" v-bind:class="dtclass">test</div>
</template>
上述執行后,div的id和class會變成 return內的對應值
如果 dtid 的值變為null或者undefind,則在頁面上會移除相應的標簽
也可使用批量綁定方式,即將所有屬性放到一個對象內,再通過v-bind綁定此對象
<div v-bind="obattr">test</div>data(){return {obattr:{id: "myid",class: "myclass"
}
}
}
class屬性綁定對象
用來動態顯示 class 屬性的屬性值
可以綁定的方式有
- 對象
- 數組
- 三元運算
- 數組嵌套對象
<template><!-- class 綁定對象 --><!-- 屬性值決定屬性是否顯示生效 --><!-- 即當 isActive 為ture時,則class屬性值顯示為 active兩個都為 ture 時,class屬性值顯示為 active text-danger --><h3 :class="{'active':isActive,'text-danger':hasError}">測試顯示class屬性值</h3><h3 :class="classObject">多個對象綁定</h3><!-- 這里運行后 class 的屬性值為 “active text-danger a b c” --><h3 :class="[classObject,mylist]">數組綁定</h3><h3 :class="[isActive ? 'active' : '']">三元運算</h3>
</template><script>export default {data(){return{isActive:true,hasError:true,classObject:{// 多個對象綁定時需要將這里的鍵與屬性名一致'active':true,'text-danger':true},mylist:["a","b","c"]}},methods:{},computed:{}}
</script>
<style>.active{color: red;font-size: 30px;}
</style>
style屬性綁定
同class屬性綁定
條件渲染
v-if 和 v-else
指令用于條件性渲染一塊內容。這塊內容只會在指令的表達式返回真值時才被渲染
v-else與v-if搭配使用,當不顯示v-if為假時,則渲染v-else的內容
<template>
<h3>條件渲染</h3>
<div v-if="flag">你能看見我么</div>
<div v-else>那你還是看看我吧</div>
</template>
<script>
export default {data(){return{flag:true}}
</script>
v-else-if
用于多重判斷
<template>
<h3>條件渲染</h3>
<div v-if="flag">你能看見我么</div>
<div v-else>那你還是看看我吧</div>
<div v-if="num == 10">10/div>
<div v-else-if="num == 20">20</div>
<div v-else="num == 30">30/div>
</template>
<script>
export default {data(){return{flag:true,num:10}}
</script>
v-show
同 v-if 的應用方式,只是這里不能接 v-else
v-if 與 v-show的區別
v-if 是“真實的”按條件染,因為它確保了在切換時,條件區塊內的事件監聽器和子組件都會被銷毀與重建
v-if 也是情性的:如果在初次染時條件值為 false,則不會做任何事。條件區塊只有當條件首次變為 true 時才被渲染。
相比之下,
v-show 簡單許多,元素無論初始條件如何,始終會被染,只有 CSS display 屬性會被切換.
總的來說,v-if 有更高的切換開銷,而 v-show 有更高的初始染開銷。
因此,如果需要頻繁切換,則使用總的來說,show 較好;
如果在運行時綁定條件很少改變,則 v-if 會更合適
列表渲染
v-for
循環新建標簽,也可以用這種方式遍歷對象的所有屬性
<p v-for="item in items"> #這里的in可以使用of替代{{ item }}
</p>
當遍歷對象的屬性時,可以使用如下獲取鍵值
<p v-for="(value,key,index) in items"> #這里的in可以使用of替代{{ value }},{{ key }},{{ index }}
</p>
對于json或者有嵌套的對象可以使用對象名.鍵名的方式調用
result:[{id:123,name:456},{id:456,name:789}]<p v-for="item in items">{{ item.id }}
</p>
也可以使用第二個參數,用來表示位置索引
result:[{id:123,name:456},{id:456,name:789}]<p v-for="(item,index) in items"> {{ item.id }}{{ index }}
</p>
通過key管理狀態
Vue 默認按照“就地更新”的策略來更新通過 or 染的元素列表。當數據項的順序改變時,Vue 不會隨之移動 DOM 元素的順序,而是就地更新每個元素,確保它們在原本指定的索引位置上渲染為了給 Vue 一個提示,以便它可以跟蹤每個節點的標識,從而重用和重新排序現有的元素,你需要為每個元素對應的塊提供一個唯一的 key attribute:
<div v-for="item of result" :key="item.id">
溫馨提示
在這里是一個通過 v-bind 綁定的特殊 attributekey推薦在任何可行的時候為 v-for 提供一個key attributekey 綁定的值期望是一個基礎類型的值,例如字符串或 number 類型
事件處理
v-on:事件類型
簡寫為 @:數據類型
<script >export default{data(){return {count:0}},methods:{addCount(){this.count++}}}
</script><template><h3>內聯事件處理器</h3><button @click="addCount">add</button><p>{{ count }}</p>
</template>
事件傳參
事件參數可以獲取 event 對象和通過事件傳遞數據
獲取event對象
methods:{addCount(e){ #這里的e就是event對象,就是js原生的eventconsole.log(e)this.count++}}
傳參則是直接在事件上傳入參數
<script >export default{data(){return {count:0}},methods:{addCount(mesg){ #這里是形參console.log(mesg)this.count++}}}
</script><template><h3>內聯事件處理器</h3><button @click="addCount('hello')">add</button> #這里傳實參<p>{{ count }}</p>
</template>
如果要在傳參的過程中還傳遞event參數則需要在傳實參時,將envent以 $event 的方式傳入
<script >export default{data(){return {count:0}},methods:{addCount(mesg,e){ #這里是形參console.log(mesg)console.log(e)this.count++}}}
</script><template><h3>內聯事件處理器</h3><button @click="addCount('hello',$event)">add</button> #這里傳實參<p>{{ count }}</p>
</template>
事件修飾符
在處理事件時調用 event.preventDefaut0 或 evet.stopPropagation0 是很常見的。盡管我們可以直接在方法內調用,但如果方法能更專注于數據邏輯而不用去處理 DOM 事件的細節會更好
為解決這一問題,Vue 為 v-on 提供了事件修飾符,常用有以下幾個:
- .stop
- .prevent
- .once
- .enter
調用方式
<標簽名 @事件類型.事件修飾符=“xxx”>
<a @click:prevent="mymythod" href="https://baidu.com">test</a>
數組變化偵測
變更方法
Vue 能夠偵聽響應式數組的變更方法,并在它們被調用時觸發相關的更新。這些變更方法包括
push()
pop()
shift()
unshitf()
splice()
sort()
reverse()
替換數組方法
變更方法,顧名思義,就是會對調用它們的原數組進行變更。相對地,也有一些不可變(immutable) 方法,下面這些都不會更改原數組,而總是返回一個新數組。當遇到的是非變更方法時,我們需要將舊的數組替換為新的
filter()
concat()
slice()
<script >export default{data(){return {names:["a","b","c"]}},methods:{addList(){// 這種方式直接自動更新,向原數組添加數據并顯示this.names.push("d") //變更方法// 這種方式不會自動更新,需要手動重新賦值才能顯示this.names = this.names.concat(["f","g"])//替換數組方法}}}
</script>
<template><button @click="addList">添加數據</button><ul><li v-for="(item,index) in names">{{ item }}</li></ul>
</template>
計算屬性
即 computed,將復雜邏輯封閉成一個方法,放入computed標簽內,在模板內直接調用方法名即可實現邏輯
<template><h3>測試</h3><p> {{ hasContent }}</p>
</template>
<script>export default {data(){return {item:{name:"myname",content: ["a","b"]}}},methods:{},// 計算屬性computed:{hasContent(){return this.item.content.length > 0 ? "yes" : "no"}}}
</script>
與方法的區別
重點區別:
計算屬性:計算屬性值會基于其響應式依賴被緩存。
一個計算屬性僅會在其響應式依賴更新時才重新計算方法:
方法調用總是會在重渲染發生時再次執行函數
偵聽器 watch
偵聽頁面數據變化
只能監聽 data 里面聲明的數據
<template><h3>測試偵聽器</h3><p>{{mesg}}</p><button @click="newMesg">修改數據</button>
</template>
<script>export default {data(){return{// mesg必須做為watch內的函數名mesg:"hello"}},methods:{newMesg(){this.mesg='update hello'}},computed:{},watch:{// newValue:改變之后的數據// oldvalue: 改變之前的數據// 函數名必須與偵聽的數據對象保持一致// 當 mesg 的值發生變化時,會自動執行這個函數mesg(newValue,oldValue){console.log(newValue+"===="+oldValue)}}}
</script>
表單輸入綁定 v-model
實時獲取用戶輸入的數據
<template><h3>測試表單輸入綁定</h3><form><input type="text" v-model="mesg"><p>{{ mesg }}</p><input type="checkbox" id="checkbox" v-model="checked"/><label for="checkbox">{{ checked }}</label></form>
</template>
<script>export default {data(){return{mesg:"",checked:false}},methods:{},computed:{}}
</script>
三人修飾符 lazy,number,trim
lazy: 只在失去焦點的時候調用
number: 只能輸入數字
trim: 去除前后空格
ref 模板引用
即使用 ref 屬性來操作DOM元素
- 內容改變:模板語法{{}}
- 屬性改變:v-band
- 事件綁定:@事件名或者v-on指令
如果沒有特別需求,不要操作DOM
步驟是在 HTML元素中設置 ref 屬性值,然后再通過 this.$refs.屬性值的方式調用
<template><h3>測試 Ref 操作 DOM</h3><div ref="container" class="container">{{ container }}</div><button @click="getEle">getEle</button>
<!-- 這里的username供后面的 $refs 調用 --><input type="text" ref="username"/><button @click="getValue">getValue</button>
</template>
<script>export default {data(){return{container:"this is container"}},methods:{getValue(){console.log(this.$refs.username.value)},getEle(){// 使用 this.$refs.屬性名的方式引用在HTML元素中ref屬性指定的屬性值調用console.log(this.$refs.container)this.$refs.container.innerHTML = "UPDATA CONT"}},computed:{}}
</script>
組件組成
概念
Vue組件是可復用的 Vue 實例。組件是 Vue 應用程序的構建塊,它們提供了一種封裝 HTML、CSS 和 JavaScript 的方式,使得可以復用組件來構建復雜的界面。
其本質上是一個對象,下面的代碼就是一個組件,即一個 .vue 文件,組件中 template 是必須的,其它可以不必需
<template><h3>測試</h3>
</template>
<script>export default {data(){},methods:{},computed:{}}
</script>
<!-- scope: 如果寫了這個屬性,則表示讓當前樣式只在當前組件中生效 -->
<style scoped>
</style>
組件最大的優勢就是可復用性
當使用構建步驟時,我們一般會將 Vue 組件定義在一個單獨的 we 文件中,這被叫做單文件組件(簡稱 SFC)
組件注冊
一個組件在使用前需要被注冊,分為全局注冊和局部注冊
全局注冊
在main.js文件中操作,這種注冊方式使組件在整個項目中都可用
import MyComponent from './App.vue'app.component('MyComponent', MyComponent)
局部注冊
局部注冊的組件需要在使用它的父組件中顯式導入,并且只能在該父組件中使用。它的優點是使組件之間的依賴關系更加明確,并且對 tree-shaking 更加友好。
<script setup>
import ComponentA from './ComponentA.vue'
</script><template><ComponentA />
</template>
如果沒有使用 <script setup>
,則需要使用 components
選項來顯式注冊:
import ComponentA from './ComponentA.js'export default {
// 這里用于注冊components: {ComponentA},setup() {// ...}
}
組件的引入
有四種引入方式
src屬性引入
即直接將script的 src 路徑設置為組件的路徑
<script src="path/to/vue.js"></script>
<script src="path/to/your-component.vue"></script>
import引入
<script setup>
// RefDemo為引入名字,可以任取,一般與文件名一致
// from 后接 路徑,表示組件所在的路徑
import RefDemo from './components/RefDemo.vue';
</script><template>
<!-- 這里需要與 import 后的名稱一致,才能在模板中顯示 --><RefDemo />
</template>
路由配置引入
在Vue路由配置中通過components
屬性引入:
const routes = [ { path: '/your-route', component: YourComponent }
];
Vue.use()方法引入
在Vue插件中通過Vue.use()
方法引入:
const YourPlugin = { install(Vue, options) { Vue.component('your-component', YourComponent); }
}; Vue.use(YourPlugin);
組件傳遞數據props
數據傳遞
注意事項:
傳遞數據,只能從父級傳遞到子級,不能反其道而行props,且porps只讀,無法在子級中修改
步驟:
- 在父模塊中引入子模塊
- 在模塊的中增加 <子模塊名 傳遞的變量名1=值1,…>
- 在子模塊export中增加 porps:[“變量名1”,“變量名2”,…]
- 在子模塊中以 模板語法 引用變量即可
father.vue
<template><Child :title=title :content=content /><div></div><h3>測試Props</h3></template>
<script >import Child from './Child.vue';export default {data(){return{title:"Father數據",content:"這是Fathercontent"}},components:{Child}}
</script>
child.vue
<template><h3>這是Child</h3><div>{{ title }}</div><div>{{ content }}</div>
</template>
<script>export default {props:["title","content"]}
</script>
數據校驗
直接在props增加以 傳遞數據變量為鍵的數據
校驗類型:
- type:數據類型
- default:父組件未傳遞變量時子組件顯示的默認值
- required:必選項,不傳會發出警告
props:{title:{type:[String,Object,Array]},content:{type:Number,// 當父組件沒有傳這個變量時顯示的默認值default:0},// 數字和字符串可以直接default,但是如果是數組和對象,必須通過工廠函數返回默認值names:{type:Array,default(){return ["空"]},// 必選項required: true} }
組件事件
在組件的模板表達式中,可以直接使用 $emit 方法觸發自定義事件觸發自定義事件的目的是組件之間傳遞數據
即實現子組件數據傳遞給父組件
步驟:
- 子組件中使用 this.$emit(方法名,參數)方式自定義一個事件
- 父組件中在引入的子組件模板內使用 @子組件方法名=“父方法名” 的方式引用
father.vue
<template><Child @send="getdata" /><div></div><h3>測試Props</h3><div>{{ mesg }}</div></template>
<script >import Child from './Child.vue';export default {data(){return{title:"Father數據",content:"這是Fathercontent",mesg:""}},components:{Child},methods:{getdata(mesg){console.log("ddddd")this.mesg=mesg}}}
</script>
Child.vue
<template><h3>這是Child</h3><button @click="sendToFather">發送數據</button>
</template>
<script>export default {methods:{sendToFather(){this.$emit("send","子組件數據")}}}
</script>
插槽 Slots
元素是一個插槽出口,標示了父元素提供的插槽內容(slot content)將在哪里被渲染
步驟
- 在父組件 template 中引入模板使用 <模板名>需要傳遞的內容</模板名> 方式
- 在子組件 template 中增加 標簽,即可在子組件中顯示
渲染作用域
插槽內容可以訪問到父組件的數據作用域,因為插槽內容本身是在父組件模板中定義的
father.vue
<template><Child><div>11111</div><!-- 這里可以動態顯示到子組件 --><h3>{{ mesg }}</h3><div>222222</div></Child>
</template>
<script >
import Child from './Child.vue';
export default {components: {Child},data() {return {mesg: "test"}}
}
</script>
child.vue
<template><h3>這是Child</h3><h3>開始引入slot</h3><slot></slot> <h3>引入完成slot</h3>
</template>
<script>
</script>
默認內容
當父組件沒有傳遞插槽給子組件時,可以在子組件child.vue中設置默認值
<template><h3>這是Child</h3><h3>開始引入slot</h3><slot>這里設置默認值</slot> <h3>引入完成slot</h3>
</template>
<script>
</script>
具名插槽
即給插槽命名,方便在子組件中指定slot引入
- 在父組件template中嵌套子組件template
- 在嵌套的template中添加屬性 v-slot:名稱 來定義slot名稱
- 在子組件中slot中添加name=名稱引用插槽
v-host可以使用#代替
father.vue
<template><Child><template v-slot:one><div>11111</div><!-- 這里可以動態顯示到子組件 --><h3>{{ mesg }}</h3></template><!-- v-slot可簡寫為 # --><template #two><div>222222</div><!-- 這里可以動態顯示到子組件 --><h3>{{ mesg2 }}</h3></template></Child>
</template>
<script >
import Child from './Child.vue';
export default {components: {Child},data() {return {mesg: "第一個插槽",mesg2: "第二個插槽"}}
}
</script>
child.vue
<template><h3>這是Child</h3><h3>開始引入slot</h3><slot name="one">默認1</slot> <h3>引入完成slot</h3> <slot name="two">默認2</slot>
</template>
<script>
</script>
在某些場景下插槽的內容可能想要同時使用父組件域內和子組件域內的數據。要做到這一點,我們需要一種方法來讓子組件在渲染時將一部分數據提供給插槽
我們也確實有辦法這么做!可以像對組件傳遞 props 那樣,向一個插槽的出口上傳遞attributes
組件的生命周期
每個Vue 組件實例在創建時都需要經歷一系列的初始化步驟,比如設置好數據偵聽,編譯模板,掛載實例到DOM,以及在數據改變時更新 DOM。在此過程中,它也會運行被稱為生命周期鉤子的函數,讓開發者有機會在特定階段運行自己的代碼