学习内容
1 2 3 4 5 6 7 8
| graph TD A[基础内容] --> B[基础语法[] B --> C[MVVM模式] C --> D[组件化] E[生命周期] --> F[动画特效] G[实战项目] --> H[环境搭建] --> I[使用Git] --> J[数据模拟] --> K[本地开发] L[联调] --> M[真机测试] --> N[上线] O[学习内容流程图]
|
学习笔记
MVVM模式:面向数据开发;MVP模式:面向dom开发
父子组件间的通信
父子组件通信是单向数据流的,子组件不能改父组件传过来的值会有警告,因为传过来的值可能别的组件也在用会影响
1 2 3 4 5 6 7 8 9 10 11 12
| props:{content:String} props:{content:[String,Number]} props:{ content:{ type:String, required:false, default:"default value", validator:function(value){ return (value.lenght>5) } } }
|
props特性和非props特性
- props特性(父组件传,子组件props参数接收):
1.可以直接在子组件使用
2.不会把传递的属性在dom中显示
- 非props特性(父组件传,子组件props参数不接收):
1.不可以在子组件中使用
2.会把属性在dom中显示出来
父-子组件通信:
- 静态Prop(传递的是字符串)
父:a=”val”
子:props:[‘a’]
- 动态Prop(传递的是JS表达式)
父:v-bind:a=”val”
子:props:[‘a’]
子-父组件通信:
子:@click=’事件1’ methods:{事件1(){this.$emit(‘事件2’,this.要传的值)}}
父:监听事件2=> v-on:事件2=”事件3”(@事件2=”事件3”) methods:{事件3(子传来的值){监听后要执行的逻辑}}
注:v-bind绑定的属性内容是js表达式:content="123"
传过去的就是数字123;content="123"
传过去的就是字符串123
1 2 3 4 5 6 7 8 9 10 11 12
| <div id="app"> <input type="text" v-model="todoValue"> <button @click="handleBtnClick">提交</button> <ul> <todo-item :content="item" :index="index" :key="index" @delete="handleItemDelete" v-for="(item,index) in list" ></todo-item> </ul> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| var TodoItem = { props:['content','index'], template:"<li @click='handleItemClick'>{{content}}</li>", methods:{ handleItemClick(){ this.$emit('delete',this.index); } } }
var app = new Vue({ el:"#app", components:{ TodoItem:TodoItem }, data:{ list:[], todoValue:"" }, methods:{ handleBtnClick: function(){ this.list.push(this.todoValue); this.todoValue = ""; }, handleItemDelete: function(index){ this.list.splice(index,1); } } })
|
v-text v-html 插值表达式
v-text和插值表达式作用一样;
v-html不同在于对标签不会进行转义,会把标签渲染在dom中
1 2 3 4 5
| <div id="app"> <p v-html="msg"></p> <p v-text="msg"></p> <p>{{msg}}</p> </div>
|
1 2 3 4 5 6
| var app = new Vue({ el:'#app', data:{ msg:"<h1>一级标题</h1>" } })
|
计算属性,方法,监听
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app">
{{fullName}} {{age}}
</div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| data:{
firstName:"Ray", lastName:"Lee",
},
computed:{ fullName:function(){ console.log("计算了一次"); return this.firstName + " " + this.lastName; }, }
|
Vue中的样式绑定
- class的对象绑定
:class="{activated: isActivated}"
通过控制class类名的显隐改变样式
- class的数组绑定
:class="[activated,activatedOne,......]"
class类名取数组内变量的值
- style样式绑定:
:style="styleObj"
:style="[styleObj,{fontSize:'20px'}]"
通过改变styleObj对象的值控制样式
Vue中的条件渲染(v-if,v-show)
false时:v-show中dom存在,只是display:none;
v-if在dom中消失
性能上v-show更好,不会重复渲染dom
1 2 3 4 5 6 7 8
|
<div v-if="show"> 用户名:<input type="text" key="username"> </div> <div v-else> 邮箱:<input type="text" key="email"> </div>
|
Vue中的列表渲染;vue中的set方法
- 数组改变实时渲染的方法
1.使用数组的七个变异方法pop()--删除数组最后一项返回删除的值;push()--数组结尾处添加一项返回新数组的长度;shift()--删除首个数组元素返回删除的值;unshift()--数组开头添加一项返回新数组的长度;splice()--拼接数组,第一个参数定义了应添加新元素的位置(拼接)。第二个参数定义应删除多少元素,其余参数定义要添加的新元素,返回包含已删除元素(如果有)的数组;sort()--对数组的元素进行排序返回排序后的数组;reverse()--反转数组
改变数组才能实时渲染页面,使用数组下标方式无法实时渲染。
变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组
2.改变数组的引用:vm.list = [1,2,5]
3.Vue.set(vm.list,2,5)
或vm.$set(vm.list,2,5)
- 对象改变实时渲染的方法:
1.改变对象的引用vm.userInfo = {name:"ray",age:22,adderss:"beijing"}
2.Vue.set(vm.userInfo,"address","beijing")
或vm.$set(vm.userInfo,"address","beijing")
使用template占位符进行列表渲染,template标签不会在dom中渲染出来,提高渲染性能
组件使用中的细节点
- table中规定
<tbody>
下必须是<tr></tr>
;ul,ol标签下规定是li标签;select标签下规定是option标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <table> <tbody> <tr is="row"></tr>
</tbody> </table> <ul> <li is="row"></li> </ul> <select> <option is="row"></option> </select>
|
在非根组件中data的定义要是一个函数data(){retrun {content:"this is content"}}
;目的是让子组件数据独立存储互不影响
ref属性写在标签上是获取的是dom元素,组件上ref获取的是组件的引用
1 2 3 4 5 6 7 8 9 10 11
| <div ref="hello" @click="handleClick"> hello world </div> methods:{ handleClick(){ console.log(this.$refs.hello.innerHTML) } }
<item ref="hello"></item>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Vue.component("item",{ template:"<div @click="handleClick">{{content}}</div>", data(){ return { content:"this is content" } } }) methods:{ handleClick(){ console.log(this.$refs.hello.content) } }
|
给组件绑定原生事件(.native)
在组件中绑定的是自定义事件,<child @click="handleClick"></child>
点击并不会触发,要想触发子组件必须用this.$emit("click")
给组件绑定原生事件<child @click.native="handleClick"></child>
点击就能触发
非父子组件间传值(Bus/总线机制/发布订阅模式/观察者模式;Vuex)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <child content="ray"></child> <child content="lee"></child>
Vue.prototype.bus = new Vue(); Vue.component("child",{ data:function(){ return { selfContent: this.content } }, props:{ content: String }, template: "<div @click="handleClick">{{selfContent}}</div>", methods:{ handleClick:function(){ this.bus.$emit("change",this.selfContent) } }, mouted: function() { var this_ = this; this.bus.$on("change",function(msg){ this_.selfContent = msg; }) } })
|
Vue中的插槽(slot)
在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的特性
2.6.0之后的插槽写法
具名插槽
1 2 3 4 5 6 7 8 9 10 11 12 13
| <base-layout> <template v-slot:header> <h1>Here might be a page title</h1> </template>
<p>A paragraph for the main content.</p> <p>And another one.</p>
<template v-slot:footer> <p>Here's some contact info</p> </template> </base-layout>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Vue.component("base-layout",{ template: `<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>` })
|
作用域插槽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user>
<current-user v-slot="slotProps"> {{ slotProps.user.firstName }} </current-user>
<current-user v-slot="{ user }"> {{ user.firstName }} </current-user> <current-user v-slot="{ user = { firstName: 'Guest' } }"> {{ user.firstName }} </current-user>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Vue.component("current-user",{ data (){ return (){ user:{ firstName:"lee", lastName:"ray" } } }, template: `<span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span>` })
|
2.6.0之前:插槽;具名插槽(已废弃)
1 2 3 4 5 6
| <body-content> <div class="header" slot="header"></div> <div class="footer" slot="footer"></div> </body-content>
|
1 2 3 4 5 6 7 8
| Vue.component("body-content",{ template: `<div> <slot name="header">default header</solt> <div class="content">content</div> <slot name="footer"></solt> </div>` })
|
1 2 3 4 5 6 7
| <child> <template slot-scope="props"> <h1>{{props.item}}</h1> </template> </child>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Vue.component("child",{ data: function(){ return { list: [1, 2, 3, 4] } }, template: `<div> <ul> <slot v-for="item in list" :item="item"></slot> </ul> </div>` })
|
动态组件(component)和v-once
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
Vue.component("child-one",{ template: "<div v-once>child-one</div>" }) Vue.component("child-two",{ template: "<div v-once>child-two</div>" }) var vm = new Vue({ el: "#root", data:{ type: "child-one" }, methods:{ handleClick: function() { this.type = (this.type === "child-one" ? "child-two" : "child-one"); } } })
|
Vue中CSS动画原理
Vue 提供了transition
的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用 v-if)
- 条件展示 (使用 v-show)
- 动态组件
- 组件根节点
1 2 3 4 5 6
| <transition> <p v-if="show">hello world</p> </transition> <button v-on:click="show = !show"> Toggle </button>
|
1 2 3 4 5 6
| .v-enter,.v-leave-to{ opacity: 0; } .v-enter-active, .v-leave-active { transition: opacity .5s; }
|
Vue中使用animate.css库;appear初次渲染;:duration显性持续时间
1 2 3 4 5 6 7 8 9 10 11 12 13
| <transition :duration="{enter:5000,leave:10000}" name="donghua" appear appear-active-class="animated swing" enter-active-class="animated swing" leave-active-class="animated shake" > <div v-show="show">hello world</div> </transition> <button @click="show = !show"> Toggle </button>
|
Vue中列表过渡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <style> .v-enter,.v-leave-to{ opacity:0; } .v-enter-active,.v-leave-active{ transition:opacity 1s; } </style> <transition-group> <div v-for="item of list" :key="item.id"> {{item.title}} </div> </transition-group> <button @click="handleAdd">add</button> <button @click="handleDel">del</button>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var vm = new Vue({ el:'#app', data:{ count:0, list:[] }, methods:{ handleAdd(){ this.list.push({ id:this.count++, title:'hello' }) }, handleDel(){ this.list.pop(); this.count--; } } })
|
Vue中的动画封装
1 2 3 4 5 6 7 8 9
| <div id="app"> <fade :show="show"> <div>hello</div> </fade> <fade :show="show"> <h1>hello</h1> </fade> <button @click="handleBtnClick">Toggle</button> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| Vue.component('fade',{ props:['show'], template:` <transition @before-enter="handleBeforeEnter" @enter="handleEnter"> <slot v-if="show"></slot> </transition> `, methods: { handleBeforeEnter(el){ el.style.color = 'red'; }, handleEnter(el,done){ setTimeout(() => { el.style.color = 'yellow'; done(); },2000) } }, }) var vm = new Vue({ el:"#app", data:{ show:false }, methods: { handleBtnClick(){ this.show = !this.show; } } })
|