angular 09年,年份較早,一開始你們是拒絕 star:javascript
react 2013年, 用戶體驗好,直接拉到一堆粉絲 star:css
vue 2014年, 用戶體驗好 做者:尤雨溪 江蘇無錫人 國人驕傲html
1:引包前端
2:啓動vue
new Vue({
el:'#app',//目的地
data:{
//保存數據的地方
},
template:`模板內容`
});
複製代碼
在vue中提供了一些對於頁面 + 數據的更爲方便的輸出,這些操做就叫作指令, 以v-xxx表示java
<div v-xxx ></div>
好比在angular中 以ng-xxx開頭的就叫作指令react
在vue中 以v-xxx開頭的就叫作指令jquery
指令中封裝了一些DOM行爲, 結合屬性做爲一個暗號, 暗號有對應的值,根據不一樣的值,框架會進行相關DOM操做的綁定ajax
v-if
是「真正」的條件渲染,由於它會確保在切換過程當中條件塊內的事件監聽器和子組件適當地被銷燬和重建。編程
v-if
也是惰性的:若是在初始渲染時條件爲假,則什麼也不作——直到條件第一次變爲真時,纔會開始渲染條件塊。
相比之下,v-show
就簡單得多——無論初始條件是什麼,元素老是會被渲染,而且只是簡單地基於 CSS 進行切換。
通常來講,v-if
有更高的切換開銷,而 v-show
有更高的初始渲染開銷。所以,若是須要很是頻繁地切換,則使用 v-show
較好;若是在運行時條件不多改變,則使用 v-if
較好。
給元素的屬性賦值
語法 在元素上 v-bind:屬性名="常量||變量名"
簡寫形式 :屬性名="變量名"
<div v-bind:原屬性名="變量"></div>
<div :屬性名="變量">
</div>
複製代碼
v-on:事件名="表達式||函數名"
@事件名="表達式"
input v-model="name"
input :value="name"
v-model: 其的改變影響其餘 v-bind: 其的改變不影響其餘
v-bind就是對屬性的簡單賦值,當內存中值改變,仍是會觸發從新渲染
v-for="item in arr"
v-for="item in obj"
v-for="(item,index) in arr" :class="index" :key='index'
[TOC]
其實忽然出來的這個名詞,會讓您不知因此然,若是你們使用過bootstrap的同窗必定會對這個名詞不陌生,咱們其實在很早的時候就接觸這個名詞
一般一個應用會以一顆嵌套的組件樹的形式來阻止:
使用局部組件的打油詩: 建子 掛子 用子
注意:在組件中這個data必須是一個函數,返回一個對象
<div id="app">
<!-- 3.使用子組件 -->
<App></App>
</div>
<script> //1.建立子組件 const App = { //必須是一個函數 data() { return { msg: '我是App組件' } }, components: { Vcontent }, template: ` <div> <Vheader></Vheader> <div> <Vaside /> <Vcontent /> </div> </div> ` } new Vue({ el: '#app', data: { }, components: { // 2.掛載子組件 App } }) </script>
複製代碼
經過Vue.component(組件名,{})
建立全局組件,此時該全局組件能夠在任意模板(template)中使用
Vue.component('Child',{
template:` <div> <h3>我是一個子組件</h3> </div> `
})
複製代碼
若是一個網頁有一個博文組件,可是若是你不能向這個組件傳遞某一篇博文的標題和內容之類想展現的數據的話,它是沒有辦法使用的.這也正是prop的由來
父組件往子組件通訊:經過Prop向子組件傳遞數據
Vue.component('Child',{
template:` <div> <h3>我是一個子組件</h3> <h4>{{childData}}</h4> </div> `,
props:['childData']
})
const App = {
data() {
return {
msg: '我是父組件傳進來的值'
}
},
template: ` <div> <Child :childData = 'msg'></Child> </div> `,
computed: {
}
}
複製代碼
網頁上有一些功能可能要求咱們和父組件組件進行溝通
子組件往父組件通訊: 監聽子組件事件,使用事件拋出一個值
Vue.component('Child', {
template: ` <div> <h3>我是一個子組件</h3> <h4>{{childData}}</h4> <input type="text" @input = 'handleInput'/> </div> `,
props: ['childData'],
methods:{
handleInput(e){
const val = e.target.value;
//使用$emit觸發子組件的事件
this.$emit('inputHandler',val);
}
},
})
const App = {
data() {
return {
msg: '我是父組件傳進來的值',
newVal:''
}
},
methods:{
input(newVal){
// console.log(newVal);
this.newVal = newVal;
}
},
template: ` <div> <div class='father'> 數據:{{newVal}} </div> <!--子組件監聽事件--> <Child :childData = 'msg' @inputHandler = 'input'></Child> </div> `,
computed: {
}
}
複製代碼
在父組件中 子組件上綁定自定義事件
在子組件中 觸發原生的事件 在事件函數經過this.$emit觸發自定義的事件
在開發中,可能會存在沒有關係的組件通訊,好比有個博客內容顯示組件,還有一個表單提交組件,咱們如今提交數據到博客內容組件顯示,這顯示有點費勁.
爲了解決這種問題,在vue中咱們可使用bus,建立中央事件總線
const bus = new Vue();
// 中央事件總線 bus
Vue.component('B', {
data() {
return {
count: 0
}
},
template: ` <div>{{count}}</div> `,
created(){
// $on 綁定事件
bus.$on('add',(n)=>{
this.count+=n;
})
}
})
Vue.component('A', {
data() {
return {
}
},
template: ` <div> <button @click='handleClick'>加入購物車</button> </div> `,
methods:{
handleClick(){
// 觸發綁定的函數 // $emit 觸發事件
bus.$emit('add',1);
}
}
})
複製代碼
父組件 provide來提供變量,而後再子組件中經過inject來注入變量.不管組件嵌套多深
Vue.component('B', {
data() {
return {
count: 0
}
},
inject:['msg'],
created(){
console.log(this.msg);
},
template: ` <div> {{msg}} </div> `,
})
Vue.component('A', {
data() {
return {
}
},
created(){
// console.log(this.$parent.$parent);
// console.log(this.$children);
console.log(this);
},
template: ` <div> <B></B> </div> `
})
new Vue({
el: '#app',
data: {
},
components: {
// 2.掛載子組件
App
}
})
複製代碼
子組件定義 slot 插槽,但並未具名,所以也能夠說是默認插槽。只要在父元素中插入的內容,默認加入到這個插槽中去
Vue.component('MBtn', {
template: ` <button> <slot></slot> </button> `,
props: {
type: {
type: String,
defaultValue: 'default'
}
},
})
const App = {
data() {
return {
}
},
template: ` <div> <m-btn>登陸</m-btn> <m-btn>註冊</m-btn> <m-btn>提交</m-btn> </div> `,
}
new Vue({
el: '#app',
data: {
},
components: {
// 2.掛載子組件
App
}
})
複製代碼
具名插槽能夠出如今不一樣的地方,不限制出現的次數。只要匹配了 name 那麼這些內容就會被插入到這個 name 的插槽中去
Vue.component('MBtn',{
template:` <button :class='type' @click='clickHandle'> <slot name='register'></slot> <slot name='login'></slot> <slot name='submit'></slot> </button> `,
props:{
type:{
type: String,
defaultValue: 'default'
}
},
methods:{
clickHandle(){
this.$emit('click');
}
}
})
const App = {
data() {
return {
}
},
methods:{
handleClick(){
alert(1);
},
handleClick2(){
alert(2);
}
},
template: ` <div> <MBtn type='default' @click='handleClick'> <template slot='register'> 註冊 </template> </MBtn> <MBtn type='success' @click='handleClick2'> <template slot='login'> 登陸 </template> </MBtn> <MBtn type='danger'> <template slot='submit'> 提交 </template> </MBtn> </div> `,
}
new Vue({
el: '#app',
data: {
},
components: {
App
}
})
複製代碼
一般狀況下普通的插槽是父組件使用插槽過程當中傳入東西決定了插槽的內容。但有時咱們須要獲取到子組件提供的一些數據,那麼做用域插槽就排上用場了
Vue.component('MyComp', {
data(){
return {
data:{
username:'小馬哥'
}
}
},
template: ` <div> <slot :data = 'data'></slot> <slot :data = 'data' name='one'></slot> </div> `
})
const App = {
data() {
return {
}
},
template: ` <div> <MyComp> <!--默認的插槽 default能夠省略--> <template v-slot:default='user'> {{user.data.username}} </template> </MyComp> <MyComp> <!--與具名插槽配合使用--> <template v-slot:one='user'> {{user.data.username}} </template> </MyComp> </div> `,
}
new Vue({
el: '#app',
data: {
},
components: {
App
}
})
複製代碼
先說一下咱們假設的應用經常使用場景,咱們已經開發了一個代辦事項列表的組件,不少模塊在用,如今要求在不影響已測試經過的模塊功能和展現的狀況下,給已完成的代辦項增長一個對勾效果。
也就是說,代辦事項列表組件要知足一下幾點
const todoList = {
data(){
return {
}
},
props:{
todos:Array,
defaultValue:[]
},
template:` <ul> <li v-for='item in todos' :key='item.id'> <slot :itemValue='item'> {{item.title}} </slot> </li> </ul> `
}
const App = {
data() {
return {
todoList: [
{
title: '大哥你好麼',
isComplate:true,
id: 1
},
{
title: '小弟我還行',
isComplate:false,
id: 2
},
{
title: '你在幹什麼',
isComplate:false,
id: 3
},
{
title: '抽菸喝酒燙頭',
isComplate:true,
id: 4
}
]
}
},
components:{
todoList
},
template: ` <todoList :todos='todoList'> <template v-slot='data'> <input type='checkbox' v-model='data.itemValue.isComplate'/> {{data.itemValue.title}} </template> </todoList> `,
}
new Vue({
el: '#app',
data: {
},
components: {
App
}
})
複製代碼
「你不須要立馬弄明白全部的東西,不過隨着你的不斷學習和使用,它的參考價值會愈來愈高。
當你在作項目過程當中,遇到了這種問題的時候,再回過頭來看這張圖
每一個 Vue 實例在被建立時都要通過一系列的初始化過程。 例如:從開始建立、初始化數據、編譯模板、掛載Dom、數據變化時更新DOM、卸載等一系列過程。 咱們稱 這一系列的過程 就是Vue的生命週期。 通俗說就是Vue實例從建立到銷燬的過程,就是生命週期。 同時在這個過程當中也會運行一些叫作生命週期鉤子的函數,這給了用戶在不一樣階段添加本身的代碼的機會,利用各個鉤子來完成咱們的業務代碼。
實例初始化以後、建立實例以前的執行的鉤子事件
Vue.component('Test',{
data(){
return {
msg:'小馬哥'
}
},
template:` <div> <h3>{{msg}}</h3> </div> `,
beforeCreate:function(){
// 組件建立以前
console.log(this.$data);//undefined
}
})
複製代碼
效果:
建立實例以前,數據觀察和事件配置都沒好準備好。也就是數據也沒有、DOM也沒生成
實例建立完成後執行的鉤子
created() {
console.log('組件建立', this.$data);
}
複製代碼
效果:
實例建立完成後,咱們能讀取到數據data的值,可是DOM還沒生成,能夠在此時發起ajax
將編譯完成的html掛載到對應的虛擬DOM時觸發的鉤子 此時頁面並無內容。 即此階段解讀爲: 即將掛載
beforeMount(){
// 掛載數據到 DOM以前會調用
console.log('DOM掛載以前',document.getElementById('app'));
}
複製代碼
效果:
編譯好的html掛載到頁面完成後所執行的事件鉤子函數
mounted() {
console.log('DOM掛載完成',document.getElementById('app'));
}
複製代碼
效果:
beforeUpdate() {
// 在更新DOM以前 調用該鉤子,應用:能夠獲取原始的DOM
console.log('DOM更新以前', document.getElementById('app').innerHTML);
},
updated() {
// 在更新DOM以後調用該鉤子,應用:能夠獲取最新的DOM
console.log('DOM更新完成', document.getElementById('app').innerHTML);
}
複製代碼
效果:
當子組件在v-if的條件切換時,該組價處於建立和銷燬的狀態
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
},
複製代碼
當配合vue的內置組件<keep-alive>
一塊兒使用的時候,纔會調用下面此方法
<keep-alive>
組件的做用它能夠緩存當前組件
activated() {
console.log('組件被激活了');
},
deactivated() {
console.log('組件被停用了');
},
複製代碼
有的時候,在不一樣組件之間進行動態切換是很是有用的,好比在一個多標籤的界面裏
const bus = new Vue();
Vue.component('TabLi', {
data() {
return {
}
},
methods: {
clickHandler(title) {
bus.$emit('handleChange', title);
}
},
props: ['tabTitles'],
template: ` <ul> <li @click='clickHandler(title)' v-for='(title,i) in tabTitles' :key='i'>{{title}}</li> </ul> `
})
const Home = {
data() {
return {
isActive:false
}
},
methods: {
handleClick(){
this.isActive = true;
}
},
template: `<div @click='handleClick' :class='{active:isActive}'>Home Component</div>`
}
const Posts = {
data() {
return {
}
},
template: `<div>Posts Component</div>`
}
const Archive = {
data() {
return {
}
},
template: `<div>Archive Component</div>`
}
Vue.component('TabComp', {
data() {
return {
title: 'Home'
}
},
created() {
bus.$on('handleChange', (title) => {
this.title = title
})
},
template: ` <div class='content'> <componet :is='title'></componet> </div> `,
components: {
Home,
Posts,
Archive
}
})
const App = {
data() {
return {
tabTitles: ['Home', 'Posts', 'Archive']
}
},
template: ` <div> <TabLi :tabTitles='tabTitles'></TabLi> <TabComp></TabComp> </div> `,
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App,
}
})
複製代碼
使用is
特性來切換不一樣的組件
當在這些組件之間切換的時候,有時候會想保持這些組件的狀態,以免反覆渲染致使的性能問題
keep-alive
<keep-alive>
<componet :is='title'></componet>
</keep-alive>
複製代碼
異步組件
在大型應用中,咱們可能須要將應用分割成小一些的代碼塊,而且只在須要的時候才從服務器加載一個模塊。爲了簡化,Vue 容許你以一個工廠函數的方式定義你的組件,這個工廠函數會異步解析你的組件定義。Vue 只有在這個組件須要被渲染的時候纔會觸發該工廠函數,且會把結果緩存起來供將來重渲染。例如:
const App = {
data() {
return {
isShow:false
}
},
methods:{
asyncLoadTest(){
this.isShow = true;
}
},
template:` <div> <button @click='asyncLoadTest'>異步加載</button> <test v-if='isShow'/> </div> `,
components:{
//異步加載組件
test:()=>import('./Test.js')
}
}
new Vue({
el:'#app',
data(){
return {
}
},
components:{
App
}
})
複製代碼
效果顯示:
儘管存在 prop 和事件,有的時候你仍可能須要在 JavaScript 裏直接訪問一個子組件。爲了達到這個目的,你能夠經過 ref
特性爲這個子組件賦予一個 ID 引用。例如:
const Test = {
template: `<div class='test'>我是測試組件</div>`
}
const App = {
data() {
return {
}
},
created() {
console.log(this.$refs.test); //undefined
},
mounted() {
// 若是是組件掛載了ref 獲取是組件對象,若是是標籤掛載了ref,則獲取的是DOM元素
console.log(this.$refs.test);
console.log(this.$refs.btn);
// 加載頁面 讓input自動獲取焦點
this.$refs.input.focus();
},
components: {
Test
},
template: ` <div> <button ref = 'btn'></button> <input type="text" ref='input'> <Test ref = 'test'></Test> </div> `
}
new Vue({
el: '#app',
data: {
},
components: {
App
}
})
複製代碼
將回調延遲到下次 DOM 更新循環以後執行。在修改數據以後當即使用它,而後等待 DOM 更新
有些事情你可能想不到,vue在更新DOM時是異步執行的.只要偵聽到數據變化,Vue將開啓一個隊列,並緩存在同一事件循環中發生的全部數據變動.若是同一個wather被屢次觸發,只會被推入到隊列中一次.這種在緩衝時去除重複數據對於避免沒必要要的計算和 DOM 操做是很是重要的。而後,在下一個的事件循環「tick」中,Vue 刷新隊列並執行實際 (已去重的) 工做
<div id="app">
<h3>{{message}}</h3>
</div>
<script src="./vue.js"></script>
<script> const vm = new Vue({ el:'#app', data:{ message:'123' } }) vm.message = 'new Message';//更新數據 console.log(vm.$el.textContent); //123 Vue.nextTick(()=>{ console.log(vm.$el.textContent); //new Message }) </script>
複製代碼
當你設置vm.message = 'new Message'
,該組件不會當即從新渲染.當刷新隊列時,組件會在下一個事件循環'tick'中更新.多數狀況咱們不須要關心這個過程,可是若是你想基於更新後的 DOM 狀態來作點什麼,這就可能會有些棘手。雖然 Vue.js 一般鼓勵開發人員使用「數據驅動」的方式思考,避免直接接觸 DOM,可是有時咱們必需要這麼作。爲了在數據變化以後等待 Vue 完成更新 DOM,能夠在數據變化以後當即使用 Vue.nextTick(callback)
。這樣回調函數將在 DOM 更新完成後被調用。
有個需求:
在頁面拉取一個接口,這個接口返回一些數據,這些數據是這個頁面的一個浮層組件要依賴的,而後我在接口一返回數據就展現了這個浮層組件,展現的同時,上報一些數據給後臺(這些數據就是父組件從接口拿的),這個時候,神奇的事情發生了,雖然我拿到數據了,可是浮層展示的時候,這些數據還未更新到組件上去,上報失敗
const Pop = {
data() {
return {
isShow:false
}
},
template:` <div v-show = 'isShow'> {{name}} </div> `,
props:['name'],
methods: {
show(){
this.isShow = true;
alert(this.name);
}
},
}
const App = {
data() {
return {
name:''
}
},
created() {
// 模擬異步請求的數據
setTimeout(() => {
this.name = '小馬哥',
this.$refs.pop.show();
}, 2000);
},
components:{
Pop
},
template: `<pop ref='pop' :name='name'></pop>`
}
const vm = new Vue({
el: '#app',
components: {
App
}
})
複製代碼
完美解決:
created() {
// 模擬異步請求的數據
setTimeout(() => {
this.name = '小馬哥',
this.$nextTick(()=>{
this.$refs.pop.show();
})
}, 2000);
},
複製代碼
因爲JavaScript的限制,Vue不能檢測對象屬性的添加和刪除
對於已經建立的實例,Vue不容許動態添加根級別的響應式屬性.可是,能夠經過Vue.set(object,key,value)
方法向嵌套獨享添加響應式屬性
<div id="app">
<h3>
{{user.name}}{{user.age}}
<button @click='handleAdd'>添加年齡</button>
</h3>
</div>
<script src="./vue.js"></script>
<script> new Vue({ el:'#app', data:{ user:{}, }, created() { setTimeout(() => { this.user = { name:'張三' } }, 1250); }, methods: { handleAdd(){ console.log(this); // 無響應式 // this.user.age = 20; // 響應式的 this.$set(this.user,'age',20); } }, }) </script>
複製代碼
this.$set(this.user,'age',20);//它只是全局Vue.set的別名
複製代碼
若是想爲已存在的對象賦值多個屬性,可使用Object.assign()
// 一次性響應式的添加多個屬性
this.user = Object.assign({}, this.user, {
age: 20,
phone: '113131313'
})
複製代碼
混入(mixin)提供了一種很是靈活的方式,來分發Vue組件中的可複用功能.一個混入對象能夠包含任意組件選項.
一個混入對象能夠包含任意組件選項。當組件使用混入對象時,全部混入對象的選項將被「混合」進入該組件自己的選項。
<div id="app">
{{msg}}
</div>
<script src="./vue.js"></script>
<script> const myMixin = { data(){ return { msg:'123' } }, created() { this.sayHello() }, methods: { sayHello(){ console.log('hello mixin') } }, } new Vue({ el: '#app', data(){ return { msg:'小馬哥' } }, mixins: [myMixin] }) 複製代碼
mixin應用
有一種很難常見的狀況:有兩個很是類似的組件,他們共享一樣的基本函數,而且他們之間也有足夠的不一樣,這時你站在了一個十字路口:我是把它拆分紅兩個不一樣的組件?仍是隻使用一個組件,建立足夠的屬性來改變不一樣的狀況。
這些解決方案都不夠完美:若是你拆分紅兩個組件,你就不得不冒着若是功能變更你要在兩個文件中更新它的風險,這違背了 DRY 前提。另外一方面,太多的屬性會很快會變得混亂不堪,對維護者很不友好,甚至是你本身,爲了使用它,須要理解一大段上下文,這會讓你感到失望。
使用混合。Vue 中的混合對編寫函數式風格的代碼頗有用,由於函數式編程就是經過減小移動的部分讓代碼更好理解。混合容許你封裝一塊在應用的其餘組件中均可以使用的函數。若是被正確的使用,他們不會改變函數做用域外部的任何東西,因此屢次執行,只要是一樣的輸入你老是能獲得同樣的值。這真的很強大。
咱們有一對不一樣的組件,他們的做用是切換一個狀態布爾值,一個模態框和一個提示框.這些提示框和模態框除了在功能,沒有其它共同點:它們看起來不同,用法不同,可是邏輯同樣
<div id="app">
<App></App>
</div>
<script src="./vue.js"></script>
<script> // 全局混入 要格外當心 每次實例建立 都會調用 Vue.mixin({ created(){ console.log('hello from mixin!!'); } }) // 抽離 const toggleShow = { data() { return { isShow: false } }, methods: { toggleShow() { this.isShow = !this.isShow } } } const Modal = { template: `<div v-if='isShow'><h3>模態框組件</h3></div>`, data() { return { } }, mixins:[toggleShow] } const ToolTip = { data() { return { } }, template: `<div v-if='isShow'><h3>提示組件</h3></div>`, mixins:[toggleShow] } const App = { data() { return { } }, template: ` <div> <button @click='handleModel'>模態框</button> <button @click='handleToolTip'>提示框</button> <Modal ref='modal'></Modal> <ToolTip ref="toolTip"></ToolTip> </div> `, components: { Modal, ToolTip }, methods: { handleModel() { this.$refs.modal.toggleShow() }, handleToolTip() { this.$refs.toolTip.toggleShow() } }, } new Vue({ el: '#app', data: {}, components: { App }, }) 複製代碼
還有2件事拜託你們
一:求贊 求收藏 求分享 求留言,讓更多的人看到這篇內容
二:歡迎添加個人我的微信
備註「資料」, 300多篇原創技術文章,海量的視頻資料便可得到
備註「加羣」,我會拉你進技術交流羣,羣裏大牛學霸具在,哪怕您作個潛水魚也會學到不少東西