组件基础
<div id="app">
<button-item v-bind:parent-val="parentVal"></button-item>
<input-item></input-item>
</div>
<script src="vue.js"></script>
<script>
/*
1.组件组成
a。data,初始数据
b.template 模版,dom
c.method
d.watch/computed
e.生命周期
f。props,接受外部的参数
2.组件注册
组件名:注册的时候使用驼峰式,在dom中使用时使用xxx-xxx
注册方式,
全局注册
缺点:即使不使用,代码会被达到生成包中
局部注册
3.数据传递
props:默认单向绑定,父级->子级
*/
// 全局注册
Vue.component("buttonItem",{
data:function(){
return{
count:0
}
},
props:["parentVal"],
methods:{
handleAdd(){
this.count++
}
},
watch:{},
computed:{},
beforeCreated(){},
created(){},
destroyed(){},
template:'<div><button @click="handleAdd">点击{{count}}</button><div>{{parentVal}}</div></div>'
})
// 局部组件
const inputItem = {
data:function(){
return{
inputVal:"我是初始值"
}
},
template:'<div><p>{{inputVal}}</p><input type="text" v-model="inputVal"/></div>'
}
const app = new Vue({
el:"#app",
data:{
parentVal:'父级的值'
},
methods:{},
components:{
inputItem
}
})
</script>
组件通信
<div id="app">
<!-- <child :msg="message" :count="count"></child> -->
<child @child-event="childEvent" :ori-msg="oriMsg"></child>
<child2 ></child2>
</div>
<script src="vue.js"></script>
<script>
/*父组件向子组件传值
1.props v-bind: 推荐
2.$parent 严格意义上,不是值传递,是直接获取父组件的数据,方法直接获取,属性先定义再在生命周期函数mounted中获取,不推荐
子组件向父组件中传值
1.通过事件传值:$emit 事件传值 父级/父组件 v-on
2.$children 和$parent使用差不多 不推荐
兄弟组件传值
1.bus中央事件总线,将bus挂砸到vue根实例的原型上 注意:注册的bus要及时销毁 推荐
beforeDestroy(){}
非空的vue实例作为中央事件,结合实例方法$on $emit
2.vuex 状态管理 state 状态管理 推荐
3.不是方法的方法 通过父组件过度 不推荐
使用:
子组件A通过事件$emit传值给父组件
父组件通过属性props传值给子组件B
深层次 不确定嵌套多层
1.依赖注入 provide(父级)/inject(子级) 不推荐直接应用于程序代码中,为高阶组件/组件库提供用例,
2.$attrs(获取绑定的属性)/inheritAttrs(是否显示隐藏)
*/
// 将bus引入的三种方式
// 1.将bus挂载到vue根实例的原型上
Vue.prototype.$bus = new Vue()
// 2.当使用工程化构建时,将bus注册到vue根对象上
// import Vue from 'vue';
// const Bus = new Vue();
// new Vue({
// el:"#app",
// data:{
// data:{
// Bus
// }
// }
// })
// 3.将bus抽离出来,组件有需要式引入,推荐
// import Vue from 'vue';
// const Bus = new Vue();
// export default Bus
const sonChild = {
data(){
return{
ms:"我是孙子组件",
}
},
inheritAttrs:false,
template:`<div>{{ms}}-----{{$attrs['ori-msg']}}</div>`
}
const child2={
// props:{
// msg:String,
// count:Number
// },
data(){
return{
ms:"我是子组件二",
sendms:"我是子组件一发送的值",
}
},
methods:{
handleClick(){
this.$bus.$emit("sendms",this.sendms)
}
},
beforeDestroy(){
this.$bus.off('sendms',this.sendms)
},
mounted(){
},
template:`<div><p @click="handleClick">{{ms}}</p></div>`
}
const child={
// props:{
// msg:String,
// count:Number
// },
data(){
return{
msg:"点击发送到父组件的值",
ms:"我是子组件一",
brotherMs:"",
count:null
}
},
inject:["oriValue"],
methods:{
handleClick(){
// 调用父级的实例方法
// this.$parent.parenetFn()
this.$emit('child-event',this.msg)
}
},
mounted(){
console.log("provide传递过来的值",this.oriValue)
this.$bus.$on("sendms",data=>{
console.log("接受到兄弟组件的值",data)
})
// this.msg = this.$parent.message
// this.count = this.$parent.count
},
beforeDestroy(){
this.$bus.off('sendms')
},
components:{
sonChild
},
inheritAttrs:false,
template:`<div><p @click="handleClick">{{ms}}</p><p>{{count}}</p><p>{{$attrs['ori-msg']}}----------</p><son-child v-bind="$attrs" ></son-child></div>`
}
const app = new Vue({
el:"#app",
data:{
oriMsg:'我是传给后代的值',
message:"父组件的值",
count:0
},
provide:{
oriValue:"源数据"
},
methods:{
parenetFn(){
console.log("父级的方法")
},
childEvent(val){
console.log("父级方法",val)
}
},
mounted(){
console.log(this.$children[0].msg)
},
components:{
child,
child2
}
})
</script>
组件深入
1插槽
<div id="app">
<child >
<template v-slot:default="slotProps">
<p >我是子组件的lastName{{slotProps.lastName}}</p>
</template>
<template v-slot:header="slotProps">
<p >我是子组件的firstName{{slotProps.firstName}}</p>
</template>
<!-- <template v-slot:footer>
<p >我是父组件传递过来的中间元素</p>
</template>
<p>footer</p>
<template v-slot:default>
<p>1</p>
<p>2</p>
<p>3</p>
</template> -->
</child>
</div>
<script src="vue.js"></script>
<script>
/*
子组件里的data必须是个函数。
1.slot:
普通插槽:父组件的dom元素插到子组件中,优先考虑父组件的dom元素,再考虑自己的默认值
具名插槽: v-slot, name,
作用域插槽:
让插槽内容可以访问到子组件中的数据,通过在子组件中绑定属性,再通过v-slot:header="slotProps"获取数据
默认插槽:<child v-slot="slotProps" ></child>
注意当同时出现多种插槽必须把每种插槽用<template>...</template>包裹写完整
*/
Vue.component("child",{
data:()=>({
lastName:"王",
firstName:"一一"
}),
template:"<div><slot v-bind:lastName='lastName'></slot><slot v-bind:firstName='firstName' name='header'></slot></div>"
// template:'<div>我是子组件---------<slot name="header"></slot><slot>我是子组件slot的默认值</slot><slot name="footer"></slot></div>'
})
const app = new Vue({
el:"#app",
data:{},
methods:{}
})
</script>
2.动态组件
<div id="app">
<keep-alive>
<component :is="currentName"></component>
</keep-alive>
<button @click="handleChange">切换组件</button>
</div>
<script src="vue.js"></script>
<script>
/*
动态组件效果即导航切换
component is
组件缓存; keep-alive
*/
Vue.component("child",{
data:()=>({
lastName:"王",
firstName:"一一"
}),
template:"<div><input type='radio'><label>组件一</label></div>"
})
Vue.component("father",{
data:()=>({
lastName:"王",
firstName:"大大"
}),
template:"<div>组件二</div>"
})
const app = new Vue({
el:"#app",
data:{
currentName:"child",
flag:true
},
methods:{
handleChange(){
this.currentName = this.flag?"father":"child";
this.flag = !this.flag
}
}
})
</script>
过渡与动画transition
<style>
/* 过渡过程中的效果,时间,过渡曲线 */
/* .xxx-enter-active,.xxx-leave-active{
transition:all 4s linear
} */
/* 进入开始状态 */
/* .xxx-enter{
opacity: 0;
}
.xxx-enter-to{
opacity: 1;
}
.xxx-leave{
opacity: 1;
}
.xxx-leave-to{
opacity: 0;
} */
/* 简写 */
/* .xxx-enter, .xxx-leave-to{
opacity: 0;
} */
/* 设置css动画 推荐 */
@keyframes bounce-in{
0%{
transform:scale(0);
}
50%{
transform:scale(1.5);
}
100%{
transform:scale(1);
}
}
@keyframes bounce-out{
0%{
transform:scale(1);
}
50%{
transform:scale(1.5);
}
100%{
transform:scale(0);
}
}
/*
第二步设置css类
*/
.xxx-enter-active{
animation:bounce-in 2s linear;
}
.xxx-leave-active{
animation:bounce-out 2s linear;
}
</style>
<body>
<div id="app">
<button @click="isShow=!isShow">显示与隐藏</button>
<transition name="xxx">
<p style="border:2px solid red" v-show="isShow">动画元素</p>
<!-- 1.点击按钮,p隐藏,会添加 xxx-leave-active(激活动画) xxx-leave-to(离开动画)
2.p元素完全隐藏完毕,移除相关类
3.再次点击按钮,会添加xxx-enter-acitve,xxx-enter-to
4.p再次显示完毕,移除相关类
-->
</transition>
</div>
<script src="vue.js"></script>
<script>
// trainsition 标签
//设置name属性 xxx
//设置css类
//设置css动画 推荐
const app = new Vue({
el:"#app",
data:{
isShow:true
},
methods:{}
})
</script>
自定义类名
<div id="app">
<button @click="isShow=!isShow">显示与隐藏</button>
<!-- <transition enter-active-class="animate__bounceIn" leave-active-class="animate__bounceOut" mode="out-in">
<p style="border:2px solid red" v-if="isShow" key="1">动画元素1</p>
<p style="border:2px solid red" v-else key="2">动画元素2</p>
</transition> -->
<transition
appear
appear-active-class="animate__bounceIn"
>
<p style="border:2px solid red;position: absolute;" v-show="isShow" key="1">动画元素1</p>
</transition>
</div>
<!--动画库-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<script src="vue.js"></script>
<script>
//1.自定义过渡类名, 配合第三方库进行使用 推荐
//2.多个元素过渡
// 注意:设置key属性进行唯一标记
// 3.过渡模式
// 默认:进入离开同时发生,设置mode
// in-out:新元素先进行过渡,完成之后,当前元素过渡离开
// out-in:当前元素先进行过渡,完成之后,新元素过渡进入
//3.使用动画库 js
//利用钩子函数
//enter leave 钩子函数中一定要使用done 进行回调,过渡立即完成,如果没有则会同时执行
// @before-enter="beforeEnter"
// @enter="enter"
// @after-enter="afterEnter"
// @before-leave="beforeLeave"
// @leave="leave"
// @after-leave="afterLeave"
// :css="false"
//3.初始渲染 appear
const app = new Vue({
el:"#app",
data:{
isShow:true
},
methods:{
beforeEnter(el){},
enter(el,done){
Velocity(
el,
{right:"400px"},
{duration:1000},
{complete:done}
)
},
afterEnter(){},
beforeLeave(){},
leave(el,done){
Velocity(
el,
{right:"-400px"},
{duration:1000},
{complete:done}
)
},
afterLeave(){},
}
})
</script>
列表
<div id="app">
<button @click="add">添加</button>
<transition-group name="xxx" tag="div">
<p v-for="(item,index) in dataList" :key="item">{{item}}<button @click="handleClick(index)">删除</button></p>
</transition>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<script src="vue.js"></script>
<script>
// 列表动画
// transition-group 以一个真实元素进行渲染
const app = new Vue({
el:"#app",
data:{
count:0,
dataList:[]
},
methods:{
add(){
this.dataList.push(this.count++)
},
handleClick(index){
this.dataList.splice(index,1)
}
}
})
</script>