渐进式框架
声明式渲染 -> 组件系统 -> 路由 -> 大规模状态管理 -> 构建工具
优势
react:函数式编程
angular:模块,依赖注入,特殊形式的组件
声明式渲染(核心)
{{data}} 使用模板语法,声明式的将数据渲染进DOM系统
过程:
新建一个vue实例,创建dom元素并给予一个id,根据id将dom元素挂载到dom实例上:el:"#app"
创建组件实例的data属性,给data新增一个age属性,使用模板语法将age声明到dom中
响应式数据绑定(MVVM)
组件化开发
页面由多个组件构成(可复用)
虚拟DOM
减少DOM操作,提升渲染性能
vue程序
<template>
<div id="app">
{{message}}
</div>
</template>
<script>
const data = {
message:'first vue'
};
const app = new Vue({
el:"#app",
data:data
})
//在组件外部定义某一个监听事件,可以使用$符号
app.$watch('message',function(newValue,oldValue){
...
})
</script>生命周期
| 钩子函数 | el | data | message(data属性) |
|---|---|---|---|
| beforeCreate | undefined | undefined | undefined |
| created | undefined | [ object Object ] | ' first vue ' |
| beforeMount | [ object HTMLDivElement ]<div id="app">...</div> | [ object Object ] | ' first vue ' |
| mounted | [ object HTMLDivElement ]<div id="app">...</div> | [ object Object ] | ' first vue ' |
| beforeUpdate | [ object HTMLDivElement ]<div id="app">...</div> | [ object Object ] | ' first vue2 ' |
| updated | [ object HTMLDivElement ]<div id="app">...</div> | [ object Object ] | ' first vue2 ' |
| beforeDestory | |||
| destoryed |
Class Style绑定
Class绑定
字符串 其实就是变量名,变量名对应的值为实际的class值
对象 { class类名(或者变量名):布尔值 ,...可以有多个 } 布尔值用来控制这个class是否生效
数组 [ 变量名1,变量名2,... ]
Style绑定
对象 { style属性名:属性值 } 属性名遇到有-的,可以用引号引起来,也可以用驼峰命名法,如:'background-color',backgroundColor
数组 [对象1,对象2,...] 这里的对象就是上面的对象形式,数组形式可以同时添加多个对象,当对象中有相同名字的属性时,后面的会覆盖前面的,名字不相同的属性则会叠加
表单修饰符
v-model.lazy 只有在失去焦点的时候才触发双向绑定值的变化
v-model.number 将用户的输入值自动转为数字,其他符号被过滤掉(底层用的parseFloat方法)
v-model.trim 过滤首尾的空白字符
组件(可复用的vue实例)组成
组件没有el属性,只有Vue的根实例才有el属性
data( function函数形式 )
props 数组,接受外部的参数
components 对象,引入的子组件
template:模板,dom元素
watch
computed
methods
生命周期的钩子函数
组件注册
全局注册:
Vue.component( '组件名' ,组件实例对象 )
上面注册时的组件名可以用驼峰命名法,但组件在父组件的HTML中引用的时候要用短横线的形式
如,注册时为‘buttomComponent’,使用的时候为<buttom-item></buttom-item>
可以随处使用,因为data是function的形式,所以每个组件之间的数据都是独立的,如果不是用function的形式,则data数据不独立,且浏览器也会报错
缺点,即使不使用,代码也会被打到生产的包中
局部注册
创建组件对象
将组件引入到需要用的页面上
在vue实例的components属性中引用
组件中的数据传递
父子组件通信
props,$emit
// section父组件 <template> <com-article :articles="articleList" @emitIndex = "onEmitIndex"></com-article> </template> <script> import comArticle from './test/article.vue' export default { name: 'HelloWorld', components: { comArticle }, data() { return { articleList: ['红楼梦', '西游记', '三国演义'], currentIndex:-1 } }, methods: { onEmitIndex(idx) { this.currentIndex = idx } } } </script> // 子组件 article.vue <template> <div @click="clickContent(1)"></div> </template> <script> export default { props: ['articles'], methods: { clickContent(index) { this.$emit('emitIndex', index) } } } </script>$children,$parent
通过$parent和$children就可以访问组件的实例, $children 的值是数组,而$parent是个对象
深层次父子间通信
依赖注入(provide,inject)父组件提供(provide)变量,子组件注入(inject)变量
<script> import comC from '../components/test/comC.vue' export default { name: "B", provide: [for,this.demo], data() { return { demo: 'demo' } }, components: { comC } } </script> //子组件C继承B <template> <div> {{demo}} </div> </template> <script> export default { name: "C", inject: ['for'], data() { return { demo: this.for } } } </script>$attrs
$attrs 获取的是用v-bind(:)绑定的值(不用props,因为和props功能是一样的)
//若想要隔代,则孙子组件上,将爷爷组件的$attrs使用v-bind绑定 <child-com2 v-bind="$attrs"></child-com2>
兄弟组件通信
直接获取组件实例 (ref,$refs),ref用在子组件上,$refs引用就指向组件实例
// 父组件 <template> <component-a ref="comA"></component-a> </template> <script> export default { mounted () { const comA = this.$refs.comA; console.log(comA.name); // Vue.js comA.sayHello(); // hello } } </script>事件总线
当作多个组件的共同事件中心,可向事件中心发送事件或者接受事件,实现多个组件的通信
//1.创建事件总线(空的vue实例)并导出,使得其他模块可以监听他 // event-bus.js import Vue from 'vue' export const EventBus = new Vue() //2.在其他模块中引入事件总线 //引入组件showNumCom,additionNumCom <template> <div> <show-num-com></show-num-com> <addition-num-com></addition-num-com> </div> </template> <script> import showNumCom from './showNum.vue' import additionNumCom from './additionNum.vue' export default { components: { showNumCom, additionNumCom } } </script> //3.additionNumCom中发送事件(事件总线.$emit(事件名称,param)) // addtionNum.vue 中发送事件 <template> <div> <button @click="additionHandle">+加法器</button> </div> </template> <script> import {EventBus} from './event-bus.js' console.log(EventBus) export default { data(){ return{ num:1 } }, methods:{ additionHandle(){ EventBus.$emit('addition', { num:this.num++ }) } } } </script> //4.showNum中接收事件(事件总线.$on(事件名称,func(param){})) // showNum.vue 中接收事件 <template> <div>计算和: {{count}}</div> </template> <script> import { EventBus } from './event-bus.js' export default { data() { return { count: 0 } }, mounted() { EventBus.$on('addition', param => { this.count = this.count + param.num; }) } } </script> //5.移除事件监听($off) import { eventBus } from 'event-bus.js' EventBus.$off('addition', {})状态管理Vuex
解决:多个视图依赖同一状态,多个视图需要更改同一状态的问题
模块:
1)state: 数据的存储
2)getters: 如vue中的计算属性一样,基于state数据的二次包装
3)mutations: 类似函数,改变state数据的唯一途径,且不能用于处理异步事件
4)actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
5)modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
插槽
父组件想向子组件传递dom元素时, 直接在使用子组件的时候包裹dom元素是无效的,如:
<child> <p>向子组件中传递dom元素</p></child>想要上面的形式生效,需要使用插槽,即在子组件中使用<slot></slot>标签,插槽主要类别有三种,分别为默认插槽,具名插槽,作用域插槽。
默认插槽
<!-- 在父组件中使用子组件child,并向子组件中传递<p>包裹的dom元素 -->
<child>
<p>向子组件中传递dom元素</p>
</child>
<!-- 其中,<slot></slot>中包裹的dom元素是父组件没有向子组件传递dom元素时,子组件所展示的默认内容
-->
<template>
<div>
...
<slot>slot中的默认内容</slot>
</div>
</template>具名插槽
在父组件中 v-slot指令(v-slot指令应该定义在temlpate模板上,而不是普通标签上,不然控制台报错),默认插槽其实就是v-slot:default;
在子组件中使用name='XXX'属性匹配父组件的v-slot:XXX,在对应的位置展示dom元素
<!-- 在父组件中使用子组件child -->
<child>
<!-- 具名插槽 -->
<template>
<p v-slot:header>向子组件中传递dom元素1</p>
</template>
<!-- 默认插槽 -->
<p>向子组件中传递dom元素2</p>
<p>2</p>
<!-- 具名插槽 -->
<template>
<p v-slot:foot>向子组件中传递dom元素3</p>
</template>
</child>
<template>
<div>
<slot name="header"></slot>
...
<slot name="footer"></slot>
<slot>slot中的默认内容</slot>
</div>
</template>作用域插槽
在父组件中使用v-slot:插槽名 = "自定义变量,用来接收子组件的data属性"接收子组件的data属性,在子组件中通过name='插槽名'匹配dom元素,再使用v-bind来获取父组件的dom元素传递过来的变量数据
<!-- 在父组件中使用子组件child -->
<child>
<!-- 自定义属性slotProps相当于传入了子组件的data对象 -->
<template v-slot:header = "slotProps">
<p>子组件中的数据{{slotProps.lastName}}</p>
</template>
<template v-slot:default = "slotProps">
<p>子组件中的数据{{slotProps.lastName}}</p>
</template>
</child>
<!-- 在子组件中 -->
data:()=>{
return {
lastName:'1',
}
}
<template>
<div>
...
<!-- 在子组件中使用v-bind接收父组件的slot传来的值 -->
<slot :lastName="lastName" name="header">slot中的默认内容</slot>
<slot :lastName="lastName" name="default">slot中的默认内容</slot>
</div>
</template>动态组件
使用<component :is="componentName"></component>动态切换组件
其中,componentName的值为子组件名称
<!-- 子组件一 -->
Vue.component('child1',{
data:()=>{
},
template:'<div>组件一</div>'
})
<!-- 子组件二 -->
Vue.component('child2',{
data:()=>{
},
template:'<div>组件二</div>'
})
<!-- 父组件中:currentName的值(子组件的名字)决定当前渲染的是哪一个子组件 -->
data()=>{
currentName:'child2'
}
<div id="app">
<component :is="currentName"></component>
</div>