MVVM是Model-View-ViewModel 的縮寫,它是一種基於前端開發的架構模式,其核心是提供對 View 和 ViewModel 的雙向數據綁定,這使得ViewModel 的狀態改變能夠自動傳遞給 View,即所謂的數據雙向綁定javascript
普一般用: v-cloak //vue 未解析以前 通常配合用 [v-cloak] {display: none;} v-bind 或者縮寫 <img :src="src" alt="" /> v-on 或者縮寫 <button @click="greet">Greet</button> v-text <span v-text="msg"></span> || <span>{{msg}}</span> //v-text 權重比{{}}高 v-html <div v-html="html"></div> v-show <div v-show="show"></div> //顯不顯示 v-if v-else-if v-else //條件 存不存在 <div v-if="status"></div> v-model //表單元素,雙向綁定 <input type="text" v-model="mess"/> v-pre //不編譯,當字符串輸出 <span v-pre>{{mess}}</span> v-once //內容解析一次,當改變值再改變也不映射修改 <span v-once>{{mess}}</span>
循環v-for Array | Object | Number | Stringhtml
這個單獨拿出來寫 更清晰: 通常jsfor in是遍歷key,而for of遍歷value 一類: data = { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } data = [{},{},{}] <div v-for="(value, index) in data"> <span>{{value}}</span> <span>{{index}}</span> </div> 二類: data={ "key1":{ "aa":"1","bb":"2" }, "key2":{ "aa":"2","bb":"4" } } <div v-for="(item,key,index) of data"> <span>{{item}}</span> <span>用of就能訪問到 key1|key2 :{{key}}</span> <span>{{index}}</span> </div>
綁定 class 對象: <div :class="{classNam1: 1 == 1, className2: 1 == 2}"></div> 單個: <div :class="classObject"></div> 數組: <div :class="[class1, class2, 'className3', active ? 'className4' : '']"></div> 對應的data data: { class1: 'className1', class2: 'className2', active: true } 綁定再方法上: <div :class="classObjectComputed"></div> computed: { classObjectComputed: function(){ return{ className1: true, className2: true } } } ----------------------------------------------------------------------- 綁定style 在對象當中,CSS 的屬性名要用駝峯式表達:fontSize 解析成 font-size 對象: <div :style="{color: color, fontSize: fontSize, backgroundColor: '#ccc'}"></div> data: { color: 'red', fontSize: '12px' } 數組: <div :style="[styleObject, {backgroundColor: '#ccc'}]"></div> data: { styleObject: { color: 'red', fontSize: '12px' } }
.**
<!--阻止事件冒泡.stop--> <div id="div1" class="stop" @click.stop="event1(1)"> <!--使用事件捕獲模式.capture--> <div id="div4" class="stop" @click.capture="event1(4)"> <!--事件只做用自己.self,相似於已阻止事件冒泡--> <div id="div7" class="stop" @click.self="event1(7)"> <!--阻止瀏覽器默認行爲.prevent--> <a href="https://m.baidu.com" target="_blank" @click.prevent="prevent">dk's github</a> <!--只做用一次.once--> <a href="https://m.baidu.com" target="_blank" @click.once="prevent">dk's github</a> <!--修飾符能夠串聯.click.prevent.once--> <a href="https://m.baidu.com" target="_blank" @click.prevent.once="prevent">dk's github</a>
實例化在哪一個容器裏 若是有多個相同的實例元素則只有第一個起效。前端
##掛載方式一: <div id="app"></div> var vm = new Vue({ el:"#app" //掛載方式一 }) ---------------- ##掛載方式二: <div id="app"></div> vm.$mount("#app"); //掛載方式二: 手動進行掛載 console.log(vm.$el) // 能夠經過實例獲取實例元素
M(Model) 數據模型層 映射到V層。vue
對象用法:vm.$set(Object, key, value) 數組用法:vm.$set(Array, index, Value)
1.對於對象,若是要給對象添加新的屬性,數據變化 視圖沒變化。java
Vue在初始化實例時進行雙向數據綁定,使用Object.defineProperty()對屬性遍歷添加 getter/setter 方法,因此setter屬性必須在 data 對象上存在時才能進行setter過程,觸發視圖響應。此時須要用到$set
#視圖不更新:this.dataform.username = '123'; // 直接賦值 在視圖上不顯示 #視圖更新:this.$set(this.dataform, 'username', '123'); //改用 $set 更新能夠在視圖上顯示
2.對於數組,因爲 JavaScript 的限制,Vue不能檢測如下變更的數組。node
//如下兩操做均沒法觸發視圖更新。其他操做正常,另外若是用到splice刪除後引發長度變化 注意 #視圖不更新:this.arr[index] = val; #視圖更新:this.$set(this.arr, index, val); #視圖不更新:this.arr.length = 2; #視圖更新:this.arr.splice(2); //對於清空數組推薦 this.arr = [];
但是若是咱們不想利用$set
去設置,非要按照咱們第一種方式去寫,能夠實現麼?答案是能夠的,就是利用$forceUpdate
了,由於你修改了數據,可是頁面層沒有變更,說明數據自己是被修改了,可是vue沒有監聽到而已,用$forceUpdate
就至關於按照最新數據給渲染一下。git
change: function(index) { this.arr[index] = '9'; this.$forceUpdate(); }, clearLen: function() { this.arr.length = 2; this.$forceUpdate(); }
元素能夠經過事件進行綁定事件github
主要是針對 data 的屬性進行操做,this的指針默認指向實例vm。
能夠像綁定普通屬性同樣在模板中綁定計算屬性api
<div id="example"> <p>本來值: "{{ basicNum }}"</p> <p>計算後的值: "{{ countNum }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { basicNum: 0 }, computed: { // 計算屬性的 getter countNum: function () { return Math.floor(this.basicNum*999/100); } } }) </script> // 設basicNum = 3 >> countNum = 29 // 設countNum = 28 報錯 由於計算屬性默認狀況下不支持set設值
默認只有getter沒有setting,只能讀取不能修改。 須要支持修改的話 要手動加上去 like this:
數組
<div id="app"> <!--fullName.get 只被調用一次--> <p>{{fullName}}</p> <p>{{fullName}}</p> <p>{{fullName}}</p> <!--每次點擊都會調用 changeName--> <input type="button" value="changeName" @click="changeName('Vue')"> </div> <script> var vm = new Vue({ el: '#app', data: { firstName:'DK', lastName: 'Lan', newName: '' }, computed: { fullName:{ get: function(){ return this.firstName + '.' + this.lastName }, set: function(newValue){ this.firstName = newValue } } }, methods: { changeName: function(txt){ this.newName = txt; //若是在這裏改變 this.fullName 的值,則會再次自動觸發對應的 getter } } }) </script>
當該屬性發生改變的時候,自動觸發,此項使用不當會影響性能,慎用
<div id="example"> <p>輸入的值: <input v-model="basicNum"></p> <p>計算後的值: "{{ countNum }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { basicNum: 0 }, watch: { // 偵聽 data屬性 這個屬性一旦變化 basicNum: function () { return Math.floor(this.basicNum*999/100); } } }) //補充 computer 和 watch 還都支持對象的寫法。 vm.$watch('obj', { // 深度遍歷 deep: true, // 當即觸發 immediate: true, // 執行的函數 handler: function(val, oldVal) {} }) </script>
不一樣:
1.computed 建立新的屬性, watch 監聽 data 已有的屬性
2.computed 會產生依賴緩存
3.當 watch 監聽 computed 時,watch 在這種狀況下無效,僅會觸發 computed.setter
{ computed: { a: { get: function(){ return ''; }, set: function(newVal){ //會觸發此項 console.log('set val %s', newVal); } } }, watch: { a: function(){ //不會被觸發 console.log('watch'); } } }
因此通常來講須要依賴別的屬性來動態得到值的時候可使用computed
,對於監聽到值的變化須要作一些複雜業務邏輯的狀況可使用watch
<div id="app"> <!-- 用法一:在雙花括號中 --> {{ money | monerFilter }} <!-- 用法二:在表達式中 版本要求2.1.0+ --> <div v-bind:id="rawId | formatId"></div> </div> <script> //定義方法一:vue選項中定義本地的過濾器 var vm = new Vue({ el: '#example', filters: { capitalize: function (value) { return "¥"+ value } } }) //定義方法二:在vue實例化以前全局定義過濾器 Vue.filter('formatId', function (value) { return value + "_total" }) new Vue({ // ... }) </script>
除了默認內置的指令 (v-model
和v-show
),Vue容許註冊自定義指令,可分全局指令和局部指令。
<div id="app"> <!--使用自定義的指令 v-myGlobalDir--> <input type="text" value="" v-myGlobalDir /> </div> <script> // 註冊指令名稱不用寫前綴 v- // 參數 element:使用指令的元素 Vue.directive('myGlobalDir', function(element){ //默認觸發鉤子函數的 inserted element.value = "世界和平"; element.focus(); }) var vm = new Vue({ el: '#app' }) </script>
<div id="app"> <!--使用自定義的指令 v-privateDir--> <input type="text" value="" v-privateDir /> </div> <script> var vm = new Vue({ el: '#app', directives: { //註冊指令名稱不用寫前綴 v- // 參數 element:使用指令的元素 privateDir: function(element){ element.style.background = '#ccc'; element.value = "世界和平"; } } }) </script>
鉤子函數能夠理解成是指令的生命週期
bind
:指令第一次綁定到元素時調用。可用於初始化。inserted
:被綁定元素插入父節點時調用update
:被綁定元素所在的模板更新時調用。componentUpdated
:指令所在組件完成一次更新後調用。unbind
:只調用一次,指令與元素解綁時調用。<div id="app"> <!--使用自定義的指令 v-demo--> <input type="text" v-model="text" v-demo="{color:'red'}"> </div> <script> Vue.directive('demo', { //先於 inserted 觸發,只調用一次 可用於初始化 bind: function(element, binding, vnode){ console.log('bind'); element.style.color = binding.value.color }, //被綁定元素插入父節點時調用 後於 bind 觸發 //參數 element: 使用指令的元素; 參數 binding: 使用指令的屬性對象; 參數 vnode: 整個 Vue 實例 inserted: function(element, binding, vnode){ console.log('inserted'); }, //被綁定元素所在的模板更新時調用,而不論綁定值是否變化 update: function(element, binding, vnode){ console.log('update'); }, //被綁定元素所在模板完成一次更新週期時調用。 componentUpdated: function(element, binding, vnode){ console.log('componentUpdated'); } }) var vm = new Vue({ el: '#app', data:{ text: '鉤子函數' } }) </script>
案例:自定義日期控件
<div id="app"> <!--直接在 jQuery 環境下使用 datepicker 插件--> <input type="text" id="datepicker" data-date-format="yyyy-mm-dd"/> <!--使用 Vue 自定義指令 v-datepicker--> <input type="text" v-datepicker data-date-format="yyyy-mm-dd"/> <input type="button" value="保存" @click="save"> <span>{{dataform.birthday}}</span> </div> //在沒有使用 Vue 前,datepicker 插件在 jQuery 的環境下是這樣使用 $('#datepicker').datepicker(); //使用 Vue 自定義指令 v-datepicker Vue.directive('datepicker', function(element, binding, vnode){ // data = dataform.birthday $(element).datepicker({ language: 'zh-CN', pickTime: false, todayBtn: true, autoclose: true }).on('changeDate', function(){ //因爲不是手動在 input 輸入值,因此雙向綁定 v-model 無效 //因此須要手動改變實例的數據模型 var data = $(element).data('model'); if(data){ // datas = ['dataform', 'birthday'] var datas = data.split('.'); //context = vm var context = vnode.context; //循環屬性自動添加 datas.map((ele, idx) => { //最後一個屬性就直接賦值 if(idx == datas.length - 1){ context[ele] = element.value } else { //動態添加屬性 context = context[ele] } }) } }) }) var vm = new Vue({ el: '#app', data: { dataform: {} }, methods: { save: function(){ //使用 $set 更新 dataform //更多 $set 的使用在下面繼續介紹 this.$set(this.dataform) } } })
組件source:
https://github.com/Wscats/vue...
1.組件命名兩個選擇:
(1)短橫線分隔命名 eg:<my-component-name>
;
(2)駝峯命名 eg:<MyComponentName>
;
2.組件data必須是個函數並return返回,強迫建立一個獨立做用域,就算組件屢次複用不相互影響。
<div id="app"> <!--組件的使用--> <private-component></private-component> </div>
//組件的定義 Vue.component(組件名稱, {template}) var vm = new Vue({ el: '#app', components:{ 'private-component': { template: '<h1>局部組件</h1>' } } })
最終渲染的效果
<div id="app"> <h1>局部組件</h1> </div>
Vue 組件默認是覆蓋渲染,爲了解決這一問題,Vue 提出了 slot 分發內容,留給父組件注入內容。
//父組件 <div id="app"> <component1> <h1>Sam</h1> <h1>Lucy</h1> </component1> </div> //組件留有slot Vue.component('component1', { template: ` <div> <h1>Tom</h1> <slot></slot> </div>` }) >>渲染出來效果 <div id="app"> <component1> <h1>Tom</h1> <h1>Sam</h1> //注入 <h1>Lucy</h1> //注入 </component1> </div>
若是要將組件裏面不一樣的子元素放到不一樣的地方,那就爲子元素加上一個屬性 slot="名稱",而後在組件定義的時候用名稱對應位置 ,其它沒有 slot 屬性的子元素將統一分發到 裏面
//父組件 <h1 slot="lucy">Lucy</h1> //在名字爲lucy的slot注入內容 //組件內部 <slot name="lucy"></slot>
(v-slot:
) 替換爲字符#
。例如v-slot:header
能夠被重寫爲#header
:
<div id="app" style="display: none;"> //切換動態組件 <input type="button" value="changeLight" @click="changeLight" /> <br/> //渲染讀取動態組件 <p :is="show"></p> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { show: 'red', }, methods:{ changeLight: function(){ this.show = this.show == 'red' ? 'green' : 'red'; } }, components: { red: { template: '<h1>Red</h1>' }, green: { template: '<h1>Green</h1>' } } }) </script>
<keep-alive>
組件實例在第一次建立的時候被緩存下來
<!-- 失活的組件將會被緩存!--> <keep-alive> <component v-bind:is="currentTabComponent"></component> </keep-alive>
2.異步組件
Vue.component('async-example', function (resolve, reject)
resolve 加載成功
reject 加載失敗
<template> <div> 組件一 延遲300毫秒,從服務器加載 組件二 不延遲從服務器加載 <template v-if="loadComponent"> <child></child> <child2></child2> </template> <button @click="toggle">點擊異步加載組件</button> </div> </template> <script> import Vue from 'vue'; const child = Vue.component('child', function (resolve) { setTimeout(function () { require(['./child.vue'], resolve) }, 3000); }); const child2 = Vue.component('child2', function (resolve) { require(['./child2.vue'], resolve) }); export default{ data: function () { return { loadComponent: false }; }, components: { child, child2, }, methods: { toggle:function () { this.loadComponent = !this.loadComponent; } } } </script>
父組件在引入子組件時上帶屬性過去,子組件props接收。
父組件在引入子組件時v-on訂閱監聽對應的數據,子組件經過$.emit數據發送給父
引入公共bus文件
參考資料:
官網:https://cn.vuejs.org/
學習筆記: https://github.com/Wscats/vue...