此篇文章是我基于研究vue文档三遍的基础上,觉得还有点难理解或者难记的知识点总结
-
列表渲染
1.渲染组件必须加key,并且属性是手动传递给组件的 <my-component v-for="(item, index) in items" v-bind:item="item" v-bind:index="index" v-bind:key="item.id"> </my-component> 2.v-for和v-if用在同一个节点上面,会先执行v-for然后再执行v-if 3.使用v-for最好加上key值,因为vue本身是基于就地更换的原则,也就是你在1-100之间再插入一个数值比如5,那么原来的5和后面的数据都会依次加一,这样的效率是非常低的,如果你传递了key做唯一的标识,那么插入的5就插在4后面了,后面的数据就不变了,只是位置挪了下
-
事件对象
-
要使用事件对象,必须在调用的时候传递$event,不能是其他的名字
-
常用的事件修饰符
.stop 阻止冒泡 .prevent 阻止默认行为 .capture 使用事件捕获 .self 自身触发 .once 触发一次
-
按键修饰符
.enter .tab .delete .esc .space .up .down .left .right 自定义修饰符 Vue.config.keyCodes.f1 = 12
-
鼠标按键修饰符
.left .right .middle
-
-
表单
表单修饰符 .lazy v-model默认是监听oninput事件的加上这个修饰符,就是监听onchange事件 <input v-model.lazy="msg" > .number 将用户输入值转换成数字 .trim 自动将用户输入的首尾空格去掉
-
组件通信
1.父组件传递信息给子组件 子组件要想得到父组件的数据,只需要在子组件内部通过props显示的声明自己想要什么属性,是不是有点意思,就像女的问男的要东西一样,我要lv包包。声明之后父组件将数据传递给子组件就ok了,如下 Vue.component('child',{ props: ['message','myMessage'], template: '<span>{{ message }}</span>' }) 在父组件中使用 <child message="hello!" :my-message="parentMsg"></child> 即可 注意:在子组件中不能修改父组件传递过来的数据,只能做备份来修改,并且引用类型要深拷贝 2.在父组件中通过传递非props属性,将自动添加到子组件根元素上面,如下 <bs-date-input data-3d-date-picker="true"></bs-date-input> 如果子组件上面已经存在了同名属性,一般都是直接替换的,但是class和style是和子组件的class和style合并的 3.子组件通知父组件 在子组件中触发某个事件同时v-on:click="childfunciton",可以通过在childfunction内部添加this.$emit('somefunction')通知触发父组件中的事件,在父组件中通过v-on:somefunction="parentfunction"接受到通知,然后触发父组件中的parentfunction事件,也就是说在父组件中,将v-on用在子组件标签上面并不是给子组件绑定事件而是监听子组件内部的消息,但是如果确实想绑定一个事件给子组件可以通过添加.native修饰符,如下 <my-component v-on:click.native="doTheThing"></my-component>这个事件将直接绑定到子组件的根元素 4.子组件父组件数据双向绑定 在父组件中的子组件标签上绑定属性使用.sync修饰符,即可完成数据双向绑定,如下 <child :foo.sync="bar"></child> 在parent组件内部定义bar属性,即可将bar值实时的通过foo传递给子组件 在子组件内部通过this.$emit('update:foo','hahahha');可以在任意时刻修改父组件中的bar值,此函数内部其实执行的是 bar => bar = val,实际上就是直接给bar赋值,但是只能采用这种方式 5.其实上面说的组件通信还是基础的,下面来看一个高级点的 <input v-model="something"> v-model其实,就是下面的简写形式 <input v-bind:value="something" v-on:input="something = $event.target.value"> 同样v-model也可以用在组件身上,就是如下的样子了 <custom-input :value="something" @input="value => { something = value }"></custom-input> 所以知道这上面两点就可以实现自定义组件v-model功能了 下面是child.vue的代码 <div> <input type="text" :value="value" @input="updateValue($event.target.value)"> {{value}} </div> export default { props: ['value'], methods: { updateValue(value){ this.$emit('input',value) } }, } 下面是father.vue的代码 <child v-model="price"></child> data () { return { price: '' } } 在子组件中的input中输入数据,可以动态的反应到父组件中,实现双向绑定 由于默认是value和input如果想改变这个默认的,可以在子组件中,使用model如下 在子组件中声明 model: { prop: 'checked', event: 'change' }, props: { checked: Boolean, value: String } 所以使用<my-checkbox v-model="foo" value="some value"></my-checkbox>其实就是下面的简写 <my-checkbox :checked="foo" @change="val => { foo = val }" value="some value"></my-checkbox> 6.非父子组件之间的通信 非父子组件之间的通信就要使用$on了 首先要有一个空的vue实例 var bus = new Vue(); 如果你使用vue的webpack项目的话,这个东西你要单独的加在一个js文件中以store.js为例,添加如下代码 import Vue from 'vue' window.bus = new Vue(); 并且还要在main.js中通过import './store.js'导入,这时就可以在vue项目全局使用bus了 如果在一个组件中需要传递消息,就使用bus.$emit('fn', 1)传递数据 在要接受数据的组件中使用,bus.$on('fn',function(value){...})即可 讲到这儿,vue最核心的部分也就将完了,弄懂这块儿东西,相信后面的学习就易如反掌了 7.使用slot实现内容分发 实际工作中组件的组成大多数是类似下面的 <parent> <child> <someother-component></someother-component> </child> </parent> slot的作用就是用来处理嵌套在组件标签内部的内容 8.单一slot 如果只有一个slot标签并且没有任何属性,slot标签将会被全部替换成嵌套在组件标签内部的内容,如果slot标签自身包裹内容,这个内容只会在组件标签内部不包含任何东西的时候展示,demo如下 如果一个child组件的模板内容如下 <div> <h2>I'm the child title</h2> <slot> 这里面的内容只会在没有插入内容时显示 </slot> </div> 然后<child>hahahhahahah</child> 那么hahahhahahah就会替换slot成为child模板的一部分 9.命名slot 可以给slot起个名字,比如<slot name="header"></slot> 然后给组件标签内容添加slot属性,属性值和上面的名字相同,就可以实现特殊指派了,如 <child> <h1 slot="header">指定的内容</h1> </child> 这样就实现的需求导入了 10.局部slot 上面讲的slot都是可以实现父组件传递数据到子组件中,现在想实现将子组件中的数据传递到slot要替换的内容中 可以在子组件中的slot插槽中添加任意属性,如 <slot text="子组件child中的数据"></slot> 然后,在子组件标签内部,如下 <parent> <child> // 必须使用template标签,并且添加scope属性,属性值props就是包含slot传递的数据对象 <template scope="props"> <span>父组件parent中的数据</span> <span>{{props.text}}</span> </template> </child> </parent> 11.动态组件 可以使用同一个绑定点,动态的切换渲染不同的组件,要实现这个功能要借助component标签和is属性 <component :is="currentView"></component> vue实例代码如下 var vm = new Vue({ el: "#example", data: { currentView: 'home' }, components: { home,posts,archive } }) 通过改变currentView的值,可以实现动态切换组件 上面这种写法可以满足局部组件,也就是你自己定义的组件的切换,但是如果你使用全局组件,比如某些UI组件库中的组件,那么就要像下面这样用 var Home = { template: ... }; var vm = new Vue({ el: "#example", data: { currentView: Home } }); 如果你想将切换渲染过的组件保留在内存中可以使用keep-alive将动态组件包裹 <keep-alive> <component :is="currentView"> ... </component> <keep-alive>
-
vue动画效果
**vue的过渡 过渡一般用于元素的插入,删除,移除 下面讲解过渡的知识 1.对单个的元素或者组件使用过渡 使用transition标签包裹要应用过渡的元素 <transition name="fade"> <p v-if="show">hello</p> </transition> 当上面的p元素在显示和隐藏中间切换时,会发生以下事情 第一,检测目标元素,自动添加或移除css过渡类名 第二,执行transition的钩子函数 第三,如果上面两步骤都没有对应的设置,那么不会应用过渡效果 2.过渡的类名 v-enter 进入的开始状态,在元素插入之前添加,在元素插入之后删除 v-enter-active 整个进入过程的状态,连续的画面,这个类就是用来定义动画的持续时间,延迟和线性函数的 v-enter-to 进入的结束状态,在元素插入之后添加,在整个enter-active结束后删除 v-leave 消失的开始状态 v-leave-active 整个消失的过程 v-leave-to 消失的结束状态 上面的这些类名的v是默认的前缀,你可以给transition标签指定name属性,用来自定义类名前缀 上面提到的元素的插入和移除就是页面上dom元素的一瞬间的状态 3.css过渡 就是指定好开始和结束的css样式,然后定义动画的执行过程,如下所示 .v-enter-active,.v-leave-active{ transition: all .3s ease; } .v-enter,.v-leave-to{ transform: translateX(10px); opacity: 0; } 4.css动画 上面都是应用的transition,这里是animation,其实类似 .v-enter-active{ animation: bounce-in .5s; } .v-leave-active{ animation: bounce-in .5s; } @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } } 5.css过渡类名 如果你使用animate.css这类的第三方css库,可以借助如下的类名 enter-class enter-active-class enter-to-class leave-class leave-active-class leave-to-class 使用demo <transition enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> 6.如何区分animation和transition 当你的动画中同时使用transition形式和animation形式的动画,必须添加type属性,指定属性值为animation或者transition 7.指定动画持续时间 vue默认的动画持续时间是基于根过渡元素,内部的子过渡元素的持续时间如果长于根过渡元素将会被忽略,所以可以在transition标签上面添加duration属性,demo如下 <transition :duration="1000">...</transition> <transition :duration="{enter: 500,leave: 800}"></transition> 8.添加动画钩子函数,这部分内容用的比较少,感兴趣自行了解 9.对初次渲染的元素添加过渡 添加appear属性 <transition appear> </transition> 添加这个属性之后,会自动应用之前指定好的enter和leave的动画,如果想实现单独的动画功能可以使用如下的方式 <transition appear appear-class="..." appear-to-class="..." appear-active-class="..." ></transition> 10.在多个元素中应用过渡 上面讨论的都是基于单个过渡元素,下面讨论多个元素的过渡 一般使用v-if/v-else在元素之前切换,相同的元素在切换的时候回复用,所以要添加key属性,如下 <transition> <button v-if="isEditing" key="save"> Save </button> <button v-else key="edit"> Edit </button> </transition> 此外,很可以添加mode属性,用来指定显示和隐藏的先后顺序 in-out 先入后出 out-in 先出后入 11.列表过渡 上面讲的都是一次过渡一个元素,现在讲一次过渡多个元素 过渡多个元素就要借助transition-group并且还要给需要过渡的元素添加key属性,可以给transition-group标签添加tag属性,指定具体渲染后的元素,还可以添加.v-move类,当元素的位置变化了,自动添加此类,此动画功能只适用于非display: inline元素 **过渡state数据 可以对数字型的数据,颜色值,这类的数据做过渡效果,主要是配合第三方库来做的,感兴趣的自己去看吧
-
render函数
讲实话这部分内容在实际使用中,几乎用不上,个人感觉vue的单文件组件,已经替代了这个的功能,所以说强大的jsx功能在vue中可能就是一个摆设而已,这也是为什么高端互联网企业选择react的原因了吧 vue的render函数说白了就是用js编写html,说实话和jsx比起来,render是非常麻烦的 vue中写render就不需要template选项了 Vue.component('demo-render',{ render: function(createElement){ // 这个函数的结果就是组件的template return createElement( // 这个函数接受三个参数 'div', 可以是组件也可以是html标签 {}, 当前vnode的属性对象,这个属性对象的介绍请看下面 [] 字符串或者数组都可以,子节点,如果子节点下面还有子节点可以再次调用createElement方法 ) } }) 属性对象的介绍 { 'class': {//v-bind:class}, style: {//v-bind:style}, attrs: {//正常的html属性如id这类的}, props: {//当前的节点是另外一个组件的话,这个就是传递给组件的属性对象}, domoProps: {//Dom节点的属性对象比如innerHTML}, on: {//v-on: 不支持修饰符}, nativeOn: {// 只能在当前的节点是其它组件的时候生效}, directives: [//自定义指令], slot: 'somename', //指定slot标签,用于插入内容,属性值是slot的name属性值 scopedSlots: { // 说实话这个东西对于初学者是很难懂的,我也是看了很多遍才明白 /* 局部插槽顾名思义,其实就是用来给子组件使用的,所以这部分内容就直 接放在render里面编写 default: props => createElement('span',props.text); 上面的代码和下面的原始写法是表达的意思是一模一样的 <template scope="props"> <span>{{props.text}}</span> </template> */ }, key: 'myKey', 就是key属性 ref: 'myRef' 当前vnode的引用 } 使用render的注意点 所有的render内部使用的vnode必须都是独一无二的,不同使用相同vnode的引用 可以在vue中使用jsx代替你,render函数的复杂写法,例子如下 render (h) { return ( <AnchoredHeading level={1}> <span>Hello</span> world! </AnchoredHeading> ) } 这就是jsx语法,通俗易懂 具体的学习地址https://github.com/vuejs/babel-plugin-transform-vue-jsx#usage 建议: 如果你被jsx的魅力所吸引,我个人觉得还是去学react的吧,在vue中的单文件组件完全可以满足你的项目开发需求,如果你在.vue文件中使用jsx或者render会变得非常奇怪,在template中使用html又在js中使用html简直就是怪胎
-
自定义指令
说实话,这部分内容我不太想写出来,一门技术总有好的和坏的反面,偶尔了解一些不太好的东西,对自己学习其他知识,可以扩展视野 这部分内容就是自己写一个指令比如v-myDirective,然后利用vue提供的钩子函数,在合适的时机触发他们。简单demo如下 Vue.directive('focus',{ // 全局指令 })或者 directive: { focus: { // 局部指令 // 可以在这里面指定钩子函数,表示在何时执行这些钩子函数 // 说白了就是利用元素的生命周期钩子实现所谓的自定义指令和vue实例的生命周期钩子本质是一样的,呵呵 bind: function(// 所有的钩子函数在这里面都可以传递参数,参数后面讲){// 当指令绑定到元素上执行,只执行一次}, inserted: // 元素插入的时候执行, update: // 元素自身更新,执行, componentUpdated: // 子组件更新执行, unbind: // 解绑的时候执行 } } 具体使用,就在需要的元素上面直接写上指令名称即可 <input v-focus> 钩子函数的参数 el // 绑定的dom元素 binding // 关于指令的相关属性对象,细节自己看 vnode ,oldVnode // 虚拟节点对象 这部分内容了解,就可以了
-
Mixins混入
这部分内容用的也比较少,不过当你的组件中有很多重复的method或者其他的选项,可以使用这个减少冗余代码 一个mixin对象可以包含实例的任何选项 var myMixin = { created: function(){ this.hello(); }, methods: { hello: function(){ console.log('hello from mixin!') } } } var Component = Vue.extend({ mixins: [myMixin] }) var component = new Component(); 混入的规则如下 1.钩子函数会放进一个队列里面,先执行mixin对象中的钩子,然后执行实例的钩子 2.methods,components,directives都会被合并成一个对象,同名的属性只会使用组件的,舍弃掉mixin对象的 3.全局混入 全局混入尽量不要用会污染所有的vue实例 Vue.mixin({ created: function() { ... } }) 4.用户自定义选项的合并 默认是组件的直接覆盖掉mixin对象的同名属性 如果想对自定义选项myOption应用自定义逻辑,可以使用如下的函数 Vue.config.optionMergeStrategies.myOption = function(toVal,fromVal){ // ... } 如果自定义选项是对象的话也可以使用methods选项的合并规则 var strategies = Vue.config.optionMergeStrategies; strategies.myOption = strategies.methods
结语
有能力的同学,我建议去学学react,毕竟到这儿,vue你已经精通了