Vue实例
注意可以注册无数个实例,但是每个同级Vue实例的作用域唯一
以下就创建了两个Vue实例
<body>
<div id="app">
{{name}}
</div>
<hr>
<div id="app2">
{{ name }}
</div>
<script>
new Vue({
el: '#app',
data: {
name: '韩梅梅'
}
})
//
new Vue({
el: '#app2',
data: {
name: '李雷雷'
}
})
// vue中可以有无数个实例, 每一个同级实例作用域唯一
</script>
还可以通过$mount('#app')进行与页面上的元素关联
数据绑定
数据绑定 数据的双向绑定
将实例(组件)里的数据和视图(页面)进行关联, 数据发生改变 页面自动变,当然当页面发生改变的时候数据也会对象发生改变
{{ }} 内部除了可以放变量 还可以放表达式
{{num+1}} {{mum?true:false}}
通过input事件实现数据绑定
原理
1. input发生改变 从视图层到数据层的数据绑定,界面触发改变数据
2. 页面对应的显示数据发生改变 从数据到视图的数据绑定 数据触发改变界面
<div id="test1">
<input type="text" @input="inputHandle" :value="msg">
{{ msg }}
</div>
<script>
/*
1. input发生改变 从视图层到数据层的数据绑定, 界面触发改变数据
2. 页面对应的显示数据发生改变 从数据到视图的数据绑定 数据触发改变界面
*/
new Vue({
el: '#test1',
data: {
msg: '123',
},
methods: {
inputHandle(e) {
console.log(e.target.value)
this.msg=e.target.value
}
}
})
</script>
也可以通过v-model实现
<input type="text" v-model="msg">
数据的双向绑定 v-model
v-model 实现双向数据绑定的一个指令 v-on v-bind的集合,
v-model是和form表单元素的value关联到一起的,返回的是表单的value
v-model 只能表单元素使用,只有表单元素提供了用户修改界面
注意:在用v-model绑定单选框的时候,需要是一个值,而要是多选框的时候需要绑定一个数组
属性绑定
属性绑定
属性:(固有属性) class id width height (自定义属性)
常规 属性名='字符串'
属性绑定 属性名="变量 或者表达式"
v-bind:属性名="变量 表达式"
简写 :属性名="变量 表达式"
通过属性绑定可以实现data中的数据控制标签的属性
类名的绑定可以使用对象,对象的key表示要添加的类名,对象的value表示该类名是否要添加
<div :class="{key:false, key2: true}"></div>//改元素就会只有key2类名
类名的绑定也可以使用数组
<div :class="['class1', 'class2']"></div>//这个元素就会有两个类名,会自动把[],去掉,会成为class='class1 class2'
组件
组件初始化
组件:组件是可以复用的Vue实例,是一个带名字可复用的vue实例,继承自实例
优点:组件解决了代码的冗余, 类似后端的函数(类)
1. 组件的创建
通过vue.extend 创建一个组件,template是字符模板
let xixi = Vue.extend({ template: '<h1>你好世界</h1>'})
2. 组件的注册
通过Vue.component('组件名',创建的组件) 注册全局组件,注册名字的时候驼峰命名和连接线命名,但是在使用的时候要用全部小写的方式
Vue.component('MyComponent',xixi)
将组件的创建和注册合并 简写
Vue.component('MyComponent',{
template:'<h1>你好世界</h1>'
})
3. 组件的使用
全局组件
通过vue.component 注册的组件是全局组件
通过实例内部的components 注册的组件是局部
在组件注册之后写的实例都可以访问,而在注册组件之前的实例不可以访问
例如:
<div id="app1">
1
<my-test></my-test>//不可以访问因为,组件在app1实例之后注册的
</div>
<hr>
<div id="app2">
2
<my-test></my-test>
</div>
<hr>
<div id="app3">
3
<my-test></my-test>
</div>
<script>
new Vue({}).$mount('#app1')
Vue.component('MyTest',{ template: "<h1>测试组件</h1>"})
Vue.component('MyTest',{ template: "<h1>测试组件222</h1>"})
new Vue({}).$mount('#app2')
new Vue({}).$mount('#app3')
局部组件
局部组件通过实例或者组件内部的components进行注册,
只能在注册的实例或者组件中进行使用,其他地方无法使用
例如:
<div id="app1">
11
<my-test/> //该组件是局部组件所以只能在app1里面用,不能在app2里面使用
</div>
<div id="app2">
<!-- <my-test/> -->
22
</div>
<script>
new Vue({
components: {
'MyTest': {
template: '<h1>测试组件</h1>'
},
// 'MyTest': {
// template: '<h1>测试组件11</h1>'
// }
}
}).$mount('#app1')
new Vue({}).$mount('#app2')
全局组件的嵌套
全局组件本身没有层级之分,根据用户的使用情况来区分父子或者兄弟
组件标签内部的内容会被忽略,除非使用插槽slot
例如:
<div id="app1">
<parent>
</parent>
</div>
<template id="parent">
<div>
这里是父组件
<son></son> //这里把子组件写在父组件里面,只在页面写父组件 <parent>
</parent> 就会显示一个父组件嵌套着子组件的样式,当然也可以用子组件套父组件,因为他们两个都是全局组件
</div>
</template>
<template id="son">
<div>
这里是子组件
<!-- <parent></parent> -->
</div>
</template>
<script>
Vue.component('parent', { template: "#parent" })
Vue.component('son', { template: "#son" })
new Vue({}).$mount('#app1')
</script>
局部组件的嵌套
局部组件的嵌套 俄罗斯套娃,局部组件在祖册完成就已经确定了嵌套关系
只能按照嵌套关系使用
例如:
<div id="app1">
<parent></parent>
</div>
<template id="parent">
<div>
这里是父组件
<son></son> //son组件只能写在parent组件里面
</div>
</template>
<template id="son">
<div>
这里是子组件
</div>
</template>
<script>
new Vue({
components: {
parent: {
template: '#parent',//parent组件是app1的局部,son又是parent的局部,因此,parent组件只能写在APP1根组件里面,而son组件只能写在parent组件里面
components: {
son: {
template: '#son',
}
}
},
// son: {
// template: '#son'
// }
}
}).$mount('#app1')
</script>
props:?
父子通信
是通过在子组件里面创建一个props属性来接收父组件传过来的参数,在父组件里用子组件的时候, 通过自定义属性将数据传递给子组件 --进行声明,然后子组件内部就会有父组件传递过来属性
例如:
Vue.component('son', {
template: '#son',
props: ['fathershow'], //在子组件里面接收父组件传递过来的参数
})
<template id="father">
<div>
这里是父组件
<son :fathershow="show"></son>//通过自定义属性,把父组件的show,传到子元素的props里面
</div>
</template>
<template id="son">
<div>
这里是子组件
<div v-show='fathershow' class="son" ></div>//在子组件里面就可以直接使用
</div>
</template>
子父通信
自定义事件
父子通信就是通过自定义事件进行传递的
在组件标签上通过@+ 自定义事件名
在组件内部通过$emit可以触发自定义事件的绑定功函数
$emit('自定义事件名',传递的参数)
事件的处理函数属于谁?
组件上的事件处理函数属于父层
自定义事件忽略大小写的,在通过emit触发的时候需要注意
总结:就是在子组件里面进行 this.$emit('事件名',参数),在子组件放到页面的时候进行触发这个自定义事件
例如
Vue.component('son', {
template: '#son',
mounted() {
this.$emit('custom-event','来自子组件的参数') //在注册子组件的时候定义一个自定义事件
}
})
<div id="app">
<son @custom-event="toast"></son> //在父元素使用son组件的时候进行触发,在这里可以触发父组件里面的toast方法,并且还可以传参,注意:事件的处理函数属于谁?
组件上的事件处理函数属于父层
</div>
//父组件
new Vue({
data: {},
methods: {
toast(value) {
alert(111+value)//value就是在子组件里面自定义事件的时候传递的参数
}
}
}).$mount('#app')
子父通信例子
通过点击子组件的按钮,进行操作父元素的显示与隐藏
<div id="app">
<div v-if='show' class="parent"></div>
<hr>
<son @son-toggle="toggle"></son>
</div>
<!-- 子组件 -->
<template id="son">
<div >
这里是子组件
<button @click="handleToggle">控制父组件div的显示隐藏</button>
</div>
</template>
<script>
// 父组件的div 由子组件控制显示隐藏
Vue.component('son', {
template: '#son',
methods: {
handleToggle() {
this.$emit('son-toggle')
},
},
mounted() {
console.log(this)
}
})
new Vue({
data: {
show: true,
},
methods: {
toggle() {
this.show = !this.show
}
}
}).$mount('#app')
亲兄弟通信
实现逻辑,兄弟1通过定义自定义事件,this.$emit()来与父元素进行通信,父元素在通过props与兄弟2进行通信
亲兄弟通信例子:通过点击兄弟2的按钮控制兄弟1的显示与隐藏, son1 存放div son2 存放控制的按钮
<div id="app">
<son1 :show="show"></son1>//自定义属性传递父组件的show数据
<hr>
<son2 @parent-show="toggle"></son2>//触发自定义事件的时候执行父组件里面的toggle函数,改变父元素里面的show
</div>
<!-- 子组件 -->
<template id="son1">
<div >
这里是子组件1
<div class="test" v-if="show"></div>//通过接收到父元素的show来进行控制显示隐藏
</div>
</template>
<!-- 子组件 -->
<template id="son2">
<div >
这里是子组件2
<button @click="toggle">切换</button>
</div>
</template>
<script>
new Vue({
data: {
show: false,
},
methods: {
toggle() {
this.show = !this.show
}
},
components: {
son1: {
template: '#son1',
props: ['show'], //1首先通过props来获取父元素的show,通过父元素的show来控制自己的显示与隐藏
mounted() {
console.log(this)
}
},
son2: {
template: '#son2',
methods: {
toggle() {
this.$emit('parent-show')//自定义一个事件,再触发这个事件的时候会改变父组件里面的show
}
}
}
}
}).$mount('#app')
表兄弟通信
通过 $on 注册一个事件 $emit 触发注册的事件 ,去实现。 只要组件能够访问到空的vue实例就能使用 $on 和$emit 方法
<div id="app">
<son1></son1>
</div>
<div id="app1">
<son2></son2>
</div>
<!-- 子组件 -->
<template id="son1">
<div >
这里是子组件1
<div class="test" v-if="show"></div>
</div>
</template>
<!-- 子组件 -->
<template id="son2">
<div >
这里是子组件2
<button @click="toggle">切换</button>
</div>
</template>
<script>
let angule = new Vue();//首先定义一个全局的VUE实例,通过angule来进行信息传递
console.log(angule)
//创建了两个Vue根元素,每个元素都有一个孩子,点击孩子2控制孩子1的隐藏与显示
new Vue({
components: {
son1: {
template: '#son1',
data() {
return {
show: true
}
},
methods: {
toggle(params) { //这里的params就是在son2创建自定义事件的时候传的参数,就会把son2里面的参数传过来
console.log('params',params)
this.show = !this.show
}
},
mounted() {
console.log('son1',angule)
angule.$on('custom', this.toggle)//2.在son1里面触发在son2创建的自定义事件,并执行this.toggle函数,并把son2创建事件的时候传的参数带到this.toggle函数中
}
},
}
}).$mount('#app')
new Vue({
components:{
son2: {
template: '#son2',
methods: {
toggle() {
angule.$emit('custom',798)//1.再点击son2里面的按钮的时候,会创建custom这个自定义事件,并且传递798参数
}
}
}
}
}).$mount('#app1')
组件切换
适用于单页面应用
通过动态组件 <component :is="type"></component> 实现,这里的type是某个组件显示,其他的不显示。 通过内置的 component 组件标签确定一块区域范围 通过is属性确定该范围内显示哪一个组件
例如实现点击首页只出现首页的组件,点击我的只显示我的组件,点击购物车只显示购物车的组件
思路:通过动态路由 <component :is="type"></component>,让在根组件只显示一个组件,type就是哪一个组件,首先一个根组件有三个子组件,分别是首页子组件,购物车子组件,我的子组件,通过点击某个元素,让type为首页,购物车,我的,再来在根组件上显示
<div id="app">
<ul>
<li @click="toggle('home')">首页</li>
<li @click="toggle('shop')">购物车</li>
<li @click="toggle('my')">我的</li>
</ul>
<hr>
<!-- 动态组件 -->
<component :is="type"></component>
</div>
<script>
const Home = {
template: "<div>这里是首页</div>"
}
const Shop = {
template: "<div>这里是Shop</div>"
}
const My = {
template: "<div>这里是My</div>"
}
new Vue({
data: {
type:'home'
},
components: { Home, Shop, My },//定义三个子组件
methods: {
toggle(params) { //通过点击事件来控制type是哪一个子组件,然后通过动态路由再来渲染哪个页面显示
this.type = params
}
}
}).$mount('#app')
过滤器
过滤器 对数据进行处理,切记处理完数据要返回,必须要return
在全局里面使用过滤器,需要写在new Vue({})实例前面
{{ 要处理的数据 | 过滤器}}
Vue.filter('过滤器的名字',(data,params1,params2...) => {
data 要处理的数据
params 其他的参数
return 处理完的数据
})
在局部的时候用:filters
例子:
<div id="app">
{{time|timeFilter(1,2,3) }}
</div>
//在全局使用的过滤器
Vue.filter('timeFilter',(data,a,b,c)=> { //这里的data就是上面调用时候的time,也就是new Vue里面的time,a,b,c就是传进去的数据,可以通过这些数据对data进行增删改查
// 处理数据逻辑
console.log(data,a,b,c)
// 返回处理完的数据
return '🙂' //返回处理完成的数据
})
new Vue({
data: {
name:'arui',
time: '11233',
},
// filters: {
// timeFilter(data,a,b,c) { //这里是局部过滤器
// console.log(data,a,b,c)
// return '呵呵'
// }
// }
}).$mount('#app')
计算属性
计算属性
computed 是实例和组件配置项的一种
也是对数据的处理,与data里的数据关联
注意:有缓存性 相关数据发生改变才会触发计算属性的重新计算,无关数据不会触发,函数 只要数据变化就会触发函数的重新计算
修改关联数据计算属性也会跟着改变
例如:
<div id="app">
{{ num }} {{ name }}
<hr>
{{double}} //调用的计算属性
<hr>
{{doubleFun()}}//调用的函数
<hr>
<button @click="add">add</button>//点击add的时候会改变num所以计算属性会触发,此时函数也会触发,只要有一个改变函数就会触发
<button @click="changeName">change</button>//点击changeName的时候,只有函数触发,因为num没有发生改变,因为在计算属性double里面只是return了num的变化,才会执行,其他的改变不会触发
</div>
new Vue({
data: {
num: 4,
name: '韩梅梅'
},
computed: {
double() {
console.log('计算属性执行了')
return (((this.num * 2 + 4) - 6) / 2 - 7) * 28
}
},
methods: {
changeName() {
this.name = "李雷雷"
},
add() {
this.num++
},
doubleFun() {
console.log('函数执行了')
return (((this.num * 2 + 4) - 6) / 2 - 7) * 28
}
}
}).$mount('#app')
监听 watch
监听简单数据改变
immediate: true, 首次也会进行监听
例如:
new Vue({
data: {
num: 4,
},
methods: {
add() {
this.num++
},
},
watch: {
num(newValue, oldValue) { //这里的num是监听data里面num的变化,在触发add函数改变num的时候就会触发
immediate: true,//首次也会监听
console.log('num变了')
console.log('new',newValue)
console.log('old',oldValue)
}
}
}).$mount('#app')
监听对象或者数组
注意: watch 不能直接监听引用类型
所以通过下面的方式进行监听
new Vue({
data: {
obj: {
name: '韩梅梅'
}
},
methods: {
changeName() {
this.obj.name = "李雷雷"
},
},
watch: {
//方法1
'obj.name':function(newV,oldV) {
console.log('obj.name变了')
}
//方法2
obj: { //这个地方的obj是data里面的obj
deep: true, // 开启深度监听
handler(newV,oldV){
console.log('深度监听',newV,oldV)//是一样的,改变后都是李雷雷,因为这里没有深复制,都是使用的同一个引用地址
console.log('验证',newV.name === oldV.name)//true,因为比较的是引用地址
}
}
} }).$mount('#app')
深度监听
深度监听与computed结合
思路:
watch 不能直接监听引用类型
computed 计算属性是和data里的数据相互关联,data改变 computed 也会改变, 从监听data里的数据转移到监听computed
实例:
new Vue({
data: {
obj: {
name: '韩梅梅'
}
},
computed: {
deepTest() {
return JSON.parse(JSON.stringify(this.obj)) //进行深复制
}
},
methods: {
changeName() {
this.obj.name = "李雷雷"
},
},
watch: {
deepTest: {
deep: true,
handler(newV,oldV) {
console.log(newV,oldV)//这里就会不一样,一个是李雷雷,一个是韩梅梅
}
}
}
}).$mount('#app')
插槽
slot
1.默认情况下组件标签内部的内容不会被渲染
2.在组件内部使用<slot>插槽来开辟一段空间来存储组件标签内部的内容,一个插槽可以将组件内部的所有标签都渲染上,要是写两个slot就会在组件内部重复显示
例如:
<son> //要想在注册的son组件里面写别的标签的时候,是不能用的,需要在创建son组件的时候写入slot
呵呵哒
<p>123</p>
<span>456</span>
</son>
<template id="son">
<div >
<slot></slot>//需要写入插槽
<hr>
这里是子组件
<hr>
<slot></slot>// 呵呵哒 <p>123</p> <span>456</span>就会渲染两次
</div>
</template>
命名插槽
<slot name="top"></slot> 目的:是为了让特定的插槽显示某一个特定的标签,之前不是命名插槽,所有标签都会显示
例如:
<div id="app">
<son>
<p slot="top">测试</p>
<span slot="bottom">下面</span>
</son>
</div>
<template id="son">
<div >
<slot name="top"></slot> //这里会显示测试
<hr>
这里是子组件
<hr>
<slot name="bottom"></slot> //这里显示下面
</div>
</template>
ref
通过ref绑定一个元素 可以获取到元素的真实dom
通过ref绑定一个组件 可以获取到组件的实例
例如:
在使用的时候先进行绑定ref,以便在父元素里面使用
<div id="app">
<p ref="hehe">绑定p元素</p> //绑定ref 为hehe
<son ref="xixi" class="son"></son> //绑定ref 为xixi,
</div>
在父元素获取p元素的真实dom,和获取son组件实例
new Vue({
data: {},
mounted() {
console.log(this)//此时this里面有一个$refs,属性是一个对象绑定的ref的dom与组件{hehe: p, xixi: VueComponent}
console.log(this.$refs.hehe)
// 父元素里获得到子组件的实例 data methods
// 获取实例里的方法都能进行修改和触发, 慎用!
console.log(this.$refs.xixi)
setTimeout(() => {
this.$refs.xixi.show = true;
// console.log(this.$refs.xixi)
// this.$refs.xixi.toggle();
},1000)
}
}).$mount('#app')
$parent
可以用来获取当前组件的父实例对象,
从而获得到数据和方法进行使用
在子组件的this里面有个$parent属性,这个属性就是改子组件的父组件实例对象,所以就可以直接通过this.$parent去访问父组件内部的方法和data等等
例如:
Vue.component('son', {
template: '#son',
methods: {
getParent() {
console.log(this)
console.log(this.$parent)
// this.$parent.name = 'hehe' //这里可以直接修改父组件的name属性
this.$parent.changeName(); //这里可以直接调用父组件的changeName方法
}
}
})
Vue 八大生命周期
创建阶段
beforeCreate:此时实例已经创建 有事件 生命周期 但是没有数据 没有真实dom
beforeCreate(){
// 实例已经创建 事件 生命周期ok 没有数据,没有真实dom
console.log('beforeCreate')
console.log(this) //VueComponent,已经有了Vue实例对象
console.log(this.num) undefined
console.log(this.$refs.p)//undefined
},
created: 创建完成 此时有数据 有this 没有真实dom
此阶段主要用于网络数据请求,
注意:此阶段也可以修改数据,但是在此阶段修改数据并不会触发updated与beforeUpdate生命周期
created() {
console.log('created')
console.log(this) //有组件实例
console.log(this.num) // 数据有
this.num = 5 //可以修改
console.log(this.$refs.p) // undefind
}
挂载阶段
beforeMount :开始挂载 和created类似 有this 有数据 无dom 用于修改数据和网络请求
beforeMount(){
console.log('beforeMount')
console.log(this)//有
console.log(this.num)//有
console.log(this.$refs.p)//无
},
mounted:挂载结束 此阶段什么都有了 ,有实例组件 有数据 有真实dom
主要操作与dom的初始化操作,注意此阶段修改数据的话就会触发updated与beforeUpdate生命周期
mounted() {
console.log('mounted')
console.log(this)//有
console.log(this.num) // 数据有
this.num = 5 //修改数据就会触发Updated的生命周期了
console.log(this.$refs.p) // 有
}
更新阶段
beforeUpdate :更新完成之前
只有在挂载之后mounted阶段更新数据的时候才会触发,在beforeMount阶段更新数据并不会触发
注意: 在这个阶段只有数据发生了改变,但是dom没有发生改变,如果dom里面用了数据渲染,那么dom里面的数据也没有发生改变<p>{{num}}</p>,此时虽然数据num改变了,但是dom还没更新改变
beforeUpdate() {
console.log('更新之前')
console.log(this)
console.log(this.num) // 更新后的数据
// this.num = 8
console.log(this.$refs.p) // 更新后的数据,注意这里console.log是异步的所以会出现更新后数据,可以通过下面innerHTML来检测
console.log(this.$refs.p.innerHTML) // 更新前的数据
setTimeout(()=>{
console.log('setTimeOut',this.$refs.p.innerHTML) // 更新后的数据
})
},
update :更新完成
在此阶段 数据与dom都是最新的 ,注意此阶段尽量不要修改数据,因为在此阶段数据已经更新完成了,你在这个阶段更新数据,他会重新再次调用更新阶段的,如果你在此阶段不停的修改数据就会不停的执行,就会出现死循环,例如this.num = Math.random();每次到这个阶段都会改数据,所以就会不停的触发更新阶段
updated() {
console.log('更新结束')
console.log(this)
this.num = 8; //上一个在mounted改变数据this.num是5,就触发了beforeUpdate与updated阶段
现在你在updated阶段改变数据,就会又调用beforeUpdate,再调用updated阶段,就会调用两次
// this.num = Math.random();//这里随机数,每次都会改变,就会不停的调用出现死循环
// 做数据修改注意在注意!!!!!
console.log(this.num) // 更新后的数据
console.log(this.$refs.p) // 更新后的数据
console.log(this.$refs.p.innerHTML) // 更新后的数据
}
销毁阶段
beforeDestroy :销毁完成之前
此阶段什么都有,但是没什么用了
beforeDestroy() {
console.log('销毁之前')
// 啥都有但是没什么用
console.log(this)//有
console.log(this.num)//有
console.log(this.$refs.p)//有
},
destroyed :销毁完成
在此阶段 Vue会回顾一生,弥补遗憾,主要用于销毁定时器,去除全局变量等等
destroyed() {
// 销毁完成 回顾一生 弥补遗憾
clearInterval(this.timmer)
console.log('销毁结束')
console.log(this)
console.log(this.num)
console.log(this.$refs.p)
}
例子:请求异步数据的时候: