Vue3.x学习笔记
进阶
全局组件
- <script src=“https://cdn.bootcdn.net/ajax/libs/vue/3.1.2/vue.global.js”>
- 国内地址
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <script src="https://unpkg.com/vue@next"></script>-->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.1.2/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const app = Vue.createApp({
//组件复用及调用
template: `
<website/>
<describe/>
<count/>
<count/>
<count/>
`,
});
//全局组件定义
app.component('website', {
template: `<h2>liuyifei</h2>
`
}) ,
app.component('describe', {
template: ` <h2>刘亦菲</h2>
`
}),
app.component('count',{
data(){
return{
count:0
}
},
template:`
<div>{{count}}</div>
<button @click="count++">count</button>
`
})
const vm = app.mount("#app");
</script>
</html>
局部组件
- 在 const app = Vue.createApp({})外层定义
const counter = {
data() {
return {
count: 0
}
},
template: `
<div>{{ count }}</div>
<button @click="count++">count</button>
`
}
- 注册
const app = Vue.createApp({
components: {
//常用简写方法
//counter
web: counter
},
})
- 调用
template: `
<website/>
<describe/>
<web/>
`,
父子组件的静态传值
- 父组件
const app = Vue.createApp({
template: `
<h2>liuyifei</h2>
<son name="刘亦菲"/>
`,
});
- 子组件
app.component('Son', {
//接收参数为数组
props:['name'],
template: `
<div>{{name}}</div>
`
})
父子组件的动态传值
- 父组件
const app = Vue.createApp({
data(){
return{
name:'刘小菲'
}
},
template: `
<h2>liuyifei</h2>
<son :name="name"/>
`,
});
- 子组件
app.component('Son', {
//接收参数为数组
props:['name'],
template: `
<div>{{name}}</div>
`
})
动态绑定函数
- 父组件
const app = Vue.createApp({
data() {
return {
name: '刘小菲',
pay: () => {
alert("收到钱")
}
}
},
/*此时的<pay/>调用了子组件
* :pay="pay"绑定了参数,两边一致*/
template: `
<h2>liuyifei</h2>
<son :name="name"/>
<pay :pay="pay"/>
`,
});
- 子组件
app.component("pay", {
/*传递参数*/
props: ['pay'],
methods: {
handleClick() {
alert("给你钱")
//调用pay()方法
this.pay()
}
},
template: `
<div @click="handleClick">马前卒</div>
`
})
组件传值时的校验操作
app.component('Son', {
props:
{
name:{
//限制类型
type:String,
//精准判断
validator(value) {
//没有则传递-1
return value.search("菲")!=-1
},
//限制必须有值
// required:true,
//默认值
default:"刘亦菲"
}
},
template: `
<div>{{ name }}</div>
`
})
单项数据流机制
- 父组件,此时counter定义在父组件中
const app = Vue.createApp({
data() {
return {
counter:0
}
},
template: `
<h2>刘亦菲</h2>
<counter :counter="counter"/>
<counter :counter="counter"/>
<counter :counter="counter"/>
`,
});
- 子组件
app.component(`counter`,{
props:[`counter`],
template:`
<div>{{ counter }}</div>
<button @click="counter++"> 按钮</button>
`
})
- 数据从父级组件传递给子组件,只能单向绑定。子组件内部不能直接修改从父组件传递过来的数据。
- 控制台告警readonly
vue.global.js:1290 [Vue warn]: Attempting to mutate prop "counter". Props are readonly.
- 修改子组件
- 使用newCounter接收this.counter,而不对父组件中的counter进行修改
app.component(`counter`,{
props:[`counter`],
data(){
//使用newCounter接收this.counter,而不对父组件中的counter进行修改
return{
newCounter:this.counter
}
},
template:`
<div>{{ newCounter }}</div>
<button @click="newCounter++"> 按钮</button>
`
})
Non-props使用技巧
- 父组件
const app = Vue.createApp({
template: `
<h2>刘亦菲</h2>
<hello style="color: #42b983" msg="liuyifei" />
`,
});
- 子组件
app.component("hello", {
//使用props:接收样式后,样式无效
// props:['style'],
// inheritAttrs默认为true,单独设置为false时Non-props不生效,设置为true时, Non-props生效
// inheritAttrs:false,
// v-bind:msg="$attrs.msg"单独接收父组件中的msg元素
// v-bind="$attrs"接收父组件中的全部元素
template: `
<h3 v-bind:msg="$attrs.msg">hello world</h3>
<h3>hello world</h3>
<h3>hello world</h3>
`
})
子组件调用父组件方法/传值/校验
- 父组件
const app = Vue.createApp({
data() {
return {
counter:0
}
},
methods:{
handleAddCounter(param){
console.log(param)
//业务逻辑在子组件
this.counter=param
}
},
//此时共享了父组件的中的counter
template: `
<h2>刘亦菲</h2>
<counter :counter="counter" @add="handleAddCounter"/>
<counter :counter="counter" @add="handleAddCounter"/>
<counter :counter="counter" @add="handleAddCounter"/>
`,
});
- 子组件
app.component(`counter`,{
props:[`counter`],
//对子组件调用父组件时,调用前需要声明
// emits:['add'],
//注意:校验和业务逻辑须同时在子组件
emits: {
add: (value) => {
return value < 20 ? true : false
}
},
methods:{
handleClick() {
this.$emit('add',this.counter+3)
}
},
template:`
<div>{{ counter }}</div>
<button @click="handleClick"> 按钮</button>
`
})
- 逻辑
- <button @click=“handleClick”> 按钮</button>调用子组件的handleClick()方法
- this.$emit(‘add’,2)调用父组件 <counter :counter=“counter” @add=“handleAddCounter”/>中 @add=“handleAddCounter”
- @add="handleAddCounter"中handleAddCounter()是父组件中的方法
- 注意:校验和业务逻辑须同时在子组件
slot
- 父组件
const app = Vue.createApp({
data() {
return {
girlfriend: `刘亦菲`
}
},
template: ` <h2>欢迎光几个菜啊-请选择您的朋友</h2>
<girlfriend>马儿扎哈</girlfriend>
<girlfriend style="color: #42b983">{{ girlfriend }}</girlfriend>
<girlfriend style="color: #42b983">
<project/>
</girlfriend>
`
})
- 子组件
app.component('girlfriend', {
data() {
return {
girlfriend: `古力娜扎`
}
},
template: `
<div>
<span>经过你的慎重考虑.最终选择了。</span>
<span>
<slot></slot>
</span>
</div>
`
})
app.component('project', {
template: `
<span style='color:blue;'>花生米</span>
`
})
- 插入的位置在 <slot></slot>之间
<span>
<slot></slot>
</span>
- 父模板里调用的数据属性,使用的都是父模板里的数据
- 子模板里调用的数据属性,使用的都是子模板里的数据
- 因此,<girlfriend style=“color: #42b983”>{{ girlfriend }}在父模板中调用,所以显示刘亦菲
插槽默认值
- 父模板
const app = Vue.createApp({
template: ` <h2>欢迎光几个菜啊-请选择您的朋友</h2>
<girlfriend>
</girlfriend>
`
})
- 子模版
- <girlfriend></girlfriend>中间没有值时,默认为子模板中的值
app.component("girlfriend", {
template: `
<div>
你选择了<slot>新垣结衣</slot>
</div>
`
})
具名插槽
- 父模板
- 调用方法:子模板标签 <pron>中接<template v-slot:one>,其中one为具名
const app = Vue.createApp({
template: ` <h2>欢迎光几个菜啊-请选择您的朋友</h2>
<pron>
<template v-slot:one><div>1.Chet选择了</div></template>
<template v-slot:two><div>3.598</div></template>
</pron>
`
})
- 子模版
app.component("pron",{
template:`
<div>
<slot name="one"></slot>
<div>2.马儿扎哈</div>
<slot name="two"></slot>
</div>
`
})
具名插槽简写
- 父模板
- 调用方法:子模板标签 <pron>中接<template #one>,其中one为具名
const app = Vue.createApp({
template: ` <h2>欢迎光几个菜啊-请选择您的朋友</h2>
<pron>
<template #one><div>1.Chet选择了</div></template>
<template #two><div>3.598套餐</div></template>
</pron>
`
})
插槽作用域
- 父模板
- v-slot="props"接收来自子模板的 :item="item"参数props(任意取名)是{ “item”: “刘亦菲” },输出时使用{{props.item}}
const app = Vue.createApp({
template: ` <h2>欢迎光几个菜啊-请选择您的朋友</h2>
<list v-slot="props">
<div>{{props.item}}</div>
</list>
`
})
- 子模版
- <slot v-for=“item in list” :item=“item” />中 v-for="item in list"遍历数据,:item="item"传递参数
app.component("list", {
data() {
return {
list: ['刘亦菲', '火龙果', 'Leru']
}
},
template: `
<div>
<slot v-for="item in list" :item="item" />
</div>
`
})
动态组件
const app = Vue.createApp({
data() {
return {
showItem: 'dajiao'
}
},
methods: {
handleTrans() {
this.showItem = this.showItem === "dajiao" ? 'liuying' : "dajiao"
}
},
template: ` <h2>欢迎光几个菜啊-请选择您的朋友</h2>
<keep-alive>
<component :is="showItem"></component>
</keep-alive>
<button @click="handleTrans">切换</button>
`
})
- <component :is=“showItem”/>指定显示哪一个组件
- <keep-alive>启用了缓存,把input框的值存了起来,使用动态组件时,经常配合标签一起使用
- <dajiao v-show=“showItem===‘dajiao’” /> 中v-show=控制是否显示
异步组件和Promise讲解
- 必须使用Vue.defineAsyncComponent()声明
app.component('async-component',Vue.defineAsyncComponent(()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve({
template:`<div>这是一个异步组件</div>`
})
},3000)
})
}))
provide和inject多级组件传值
- 父模板
- 数据项的下面声明一个provide
const app = Vue.createApp({
data(){
return {house:'北京别墅一套'}
},
provide:{
newHouse:'北京200平方房子一套'
},
template: `
<div>我有一套房子,我先传给我的儿子</div>
<child :house="house" />
`
})
- 子模版
- 用inject接收
app.component('child-child',{
props:['house'],
inject:['newHouse'],
template:`
<div>我是孙子,等待接收房子</div>
<div>孙子接收{{house}},{{newHouse}}</div>
`
})
动画
CSS样式中的动画效果
- 创建一个CSS区域,然后编写样式。这时候我们要使用CSS中的animation属性,然后再使用关键帧keyframes指定详细的动画过程。
- 样式
<style>
.animation {
animation: leftToRight 3s;
}
@keyframes leftToRight {
0% {
transform: translateX(0px);
}
25% {
transform: translateX(25px);
}
50% {
transform: translateX(50px);
}
75% {
transform: translateX(25px);
}
100% {
transform: translateX(0px);
}
}
</style>
- 做一个数据项,这个数据项的作用就是控制动画起不起作用
- 必须做成对象,直接使用animation无效
data() {
return {
isAnimate: {
animation: false
}
}
},
- 方法
methods: {
handleClick() {
this.isAnimate.animation = !this.isAnimate.animation
}
- 模板
template: `
<div :class="isAnimate">Vue学习笔记</div>
<div><button @click="handleClick">启动/关闭</button></div>
`
Vue控制过渡效果
- 样式
<style>
.transition {
/*过渡的事件 内容 过渡速度,具体见下表*/
transition: 3s background-color ease;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
</style>
- transition 变化速度
值 | 描述 |
---|---|
linear | 规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。(匀速) |
ease | 规定慢速开始,然后变快,然后慢速结束的过渡效果(cubic-bezier(0.25,0.1,0.25,1))(相对于匀速,中间快,两头慢)。 |
ease-in | 规定以慢速开始的过渡效果(等于 cubic-bezier(0.42,0,1,1))(相对于匀速,开始的时候慢,之后快)。 |
ease-out | 规定以慢速结束的过渡效果(等于 cubic-bezier(0,0,0.58,1))(相对于匀速,开始时快,结束时候间慢,)。 |
ease-in-out | 规定以慢速开始和结束的过渡效果(等于 cubic-bezier(0.42,0,0.58,1))(相对于匀速,(开始和结束都慢)两头慢)。 |
cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值。 |
- 注意:数据驱动
data() {
return {
css: {
transition: true,
red: true,
yellow: false
}
}
},
- 方法
methods: {
hanldClick() {
this.css.red = !this.css.red
this.css.yellow = !this.css.yellow
}
},
Vue3制作过渡效果一
- 样式
<style>
@keyframes comein {
0% {
transform: translateX(-150px)
}
100% {
transform: translateX(0px)
}
}
@keyframes comeout {
0% {
transform: translateX(0px)
}
100% {
transform: translateX(-150px)
}
}
/*固定的CSS样式写法v-enter-active意思是进入时采用何种动画方式*/
.v-enter-active {
animation: comein 1s;
}
/*固定的CSS样式写法v-leave-active意思是退出时采用何种动画方式*/
.v-leave-active {
animation: comeout 1s;
}
</style>
-
过渡的类名 <transition>
在进入/离开的过渡中,会有 6 个 class 切换。
- v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
- v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
- v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
- v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
- 模板
- 使用<transition>套在显示内容的外层,会自动加入动画效果
template: `
<transition><h3 v-show="isShow">Vue动画笔记</h3></transition>
<button @click="handleClick">切换</button>
`
Vue3制作过渡效果二
.v-enter-from,.v-leave-to{
opacity: 0;
}
.v-enter-to,.v-leave-from{
opacity: 1;
}
.v-enter-active {
transition: opacity 3s ease-out;
}
.v-leave-active {
transition: opacity 3s ease-out;
}
自定义标签一
<style>
.chet-enter-active {
animation: comein 1s;
}
.chet-leave-active {
animation: comeout 1s;
}
</style>
template: `
<transition name="chet"><h3 v-show="isShow">Vue动画笔记</h3></transition>
<button @click="handleClick">切换</button>
`
自定义标签二
<style>
.come {
animation: comein 1s;
}
.go {
animation: comeout 1s;
}
</style>
template: `
<transition enter-active-class="come"
leave-active-class="go"
><h3 v-show="isShow">Vue动画笔记</h3></transition>
<button @click="handleClick">切换</button>
`
第三方动画库Animate使用
- 库标签
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
- 建议本地配置,下载地址https://github.com/animate-css/animate.css/releases
<link href="./animate.css" rel="stylesheet" type="text/css"/>
- 模板
template: `
<transition enter-active-class="animate__animated animate__bounce"
leave-active-class="animate__animated animate__flash"
><h3 v-show="isShow">Vue动画笔记</h3></transition>
<button @click="handleClick">切换</button>
`
过渡和动画协调
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo06</title>
<style>
@keyframes comein {
0% {
transform: translateX(-120px)
}
100% {
transform: translateX(0px)
}
}
@keyframes comeout {
0% {
transform: translateX(0px)
}
100% {
transform: translateX(-120px)
}
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-enter-to,
.v-leave-from {
opacity: 1;
}
.v-enter-active {
animation: comein 3s;
transition: opacity 3s ease-out;
}
.v-leave-active {
animation: comeout 3s;
transition: opacity 3s ease-out;
}
</style>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.0.2/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
isShow: false
}
},
methods: {
hanldClick() {
this.isShow = !this.isShow
}
},
template: `
<transition>
<div v-if="isShow">技术胖讲程序</div>
</transition>
<button @click="hanldClick">切换动画</button>
`
})
const vm = app.mount("#app")
</script>
- 过渡和动画时长不一致的处理
- 在标签上加入type='animation’属性,意思是不管过渡时长是多少,动画结束,整个过程结束。
template: `
<transition type="animation">
<div v-if="isShow">技术胖讲程序</div>
</transition>
<button @click="hanldClick">切换动画</button>
`
- 属性控制动画和过渡时长
- 不管CSS中的动画和过渡时长,以标签为准。可以绑定属性 来控制时长,意思是1秒后,结束动画和过渡。
template: `
<transition :duration="1000">
<div v-if="isShow">技术胖讲程序</div>
</transition>
<button @click="hanldClick">切换动画</button>
- duration除了能写一个数字之外,还可以写对象进去,分别控制进入和退出时长
<transition :duration="{enter:1000,leave:3000}">
JS+Vue3制作动画和钩子函数
<script>
const app = Vue.createApp({
data() {
return {
isShow: false
}
},
methods: {
handleClick() {
this.isShow = !this.isShow
},
handleBeforeEnter(element) {
element.style.color = 'red'
},
handleEnterActive(element, done) {
let interval = setInterval(() => {
let color = element.style.color;
if (color == 'red') {
element.style.color = "green"
} else {
element.style.color = "red"
}
}, 500);
setTimeout(() => {
clearInterval(interval)
done()
}, 1500);
},
handleEnterEnd(element) {
element.style.color = "blue"
},
},
//js钩子函数
//进入
// @before-enter="handleBeforeEnter"
// @enter="handleEnterActive"
// @after-enter="handleEnterEnd"
//退出
// @before-leave=""
// @leave=""
// @leave-enter=""
// :css="false" 关闭css动画
template: `
<transition :css="false"
@before-enter="handleBeforeEnter"
@enter="handleEnterActive"
@after-enter="handleEnterEnd"
><h3 v-show="isShow">Vue动画笔记</h3></transition>
<button @click="handleClick">切换</button>
`
})
const vm = app.mount("#app")
</script>
双DOM元素动画的实现
<style>
.v-enter-from,.v-leave-to{
opacity: 0;
}
.v-enter-to,.v-leave-from{
opacity: 1;
}
.v-enter-active,.v-leave-active{
transition: opacity 2s ease-in;
}
</style>
- mode="out-in"先执行退出动画,再执行进入动画
- appear刷新页面时执行进入动画
template: `
<transition mode="out-in" appear>
<div v-if="isShow">大脚进入了电影院</div>
<div v-else>晓红进入了电影院</div>
</transition>
<button @click="handleClick">切换动画</button>`
双组件切换动画的实现
- 动态实现
<script>
//局部组件
const Dajiao = {
template: `
<div>大脚进入了电影院</div>
`
}
const Xiaohong = {
template: `
<div>晓红进入了电影院</div>
`
}
const app = Vue.createApp({
data() {
return {
isShow: false,
component:'da-jiao'
}
},
methods: {
handleClick() {
this.isShow = !this.isShow
this.component=this.component==='da-jiao' ?'xiao-hong' : 'da_jiao'
}
},
//注册局部组件
components: {
'da-jiao': Dajiao,
'xiao-hong': Xiaohong
},
template: `
<transition mode="out-in" appear>
<!-- //静态实现 <da-jiao v-if="isShow"/>-->
<!-- // <xiao-hong v-else/>-->
<component :is="component"></component>
</transition>
<button @click="handleClick">切换动画</button>`
})
const vm = app.mount("#app")
</script>