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...