Vue3学习
B站:学习笔记
视频地址:https://www.bilibili.com/video/BV1FP4115739/
安装相应环境
- 安装node.js
https://nodejs.org/en/
- 安装VScode
https://code.visualstudio.com/
一、Vite2
前置知识:
https://vitejs.cn/guide/
二、搭建第一个Vite项目
注意:需要vite需要node.js版本>=12.0.0
npm init vite
1.运行:
PS E:\html\vue3-demo> npm init vite
Need to install the following packages:
create-vite@3.2.1
Ok to proceed? (y) y
√ Project name: ... vue3-demo
√ Select a framework: » Vue
√ Select a variant: » JavaScript
Scaffolding project in E:\html\vue3-demo\vue3-demo...
Done. Now run:
cd vue3-demo
npm install
npm run dev
2.进入创建好的文件夹,运行npm install
cd vue3-demo
npm install
3.运行起来
npm run dev
访问以下网址:
运行成功!!
public目录下资源浏览器可以直接访问:
index.html:程序入口,type="module"加上浏览器支持模块化,才能导入Vue模块。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>第一个vite程序</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/main.js"></script>
</body>
</html>
main.js:用于引入Vue后缀的文件,
import { createApp } from 'vue'//导入vue的createApp模块
import App from './App.vue' //导入自己新建的App.vue模块
const app = createApp(App)//创建vue模块
app.mount('#app')//加载vue模块与index.html的div的id对应
App.vue基础模板:单页面应用,以后的组件都在App.vue这个页面挂载。
<script setup>
</script>
<template>
<div>
app123
</div>
</template>
<style lang="css">
div {
font-size: 20px;
}
</style>
1、App.vue基础模板
简写
-
v-bind 对应 :
后面跟上标签的属性::style=“{‘textDecoration’ : ui }”
主要用于ref定义的属性能用于标签属性 -
v-on 对应 @
主要用于事件触发调用函数
1.导入其他的vue文件
script 里加上 setup,导入其他的vue文件才能作为标签使用
<script setup>
import Demo from '../src/components/Demo.vue'
</script>
<template>
<Demo></Demo><!--导入的vue模板文件,可以直接当作标签使用!!-->
</template>
<style lang="css">
div {
font-size: 20px;
}
</style>
2、ref模块
1.导入ref模块,用作定义数据或者类
<script setup>
import {ref} from 'vue'
</script>
2.使用方法
<script setup>
import { ref } from 'vue';
const count = ref(0)//定义为0,也可以是字符串,布尔类型
const handleClick = function(){
count.value++//script里操作值要加value
}
</script>
<template>
<div>
{{count}} //这里不用加value,vue已经帮我们自动获取了,双向绑定
<button @click="handleClick">add</button>//@click与v-on:click等价,缩写
</div>
</template>
<style lang="css">
</style>
3、模板语法
<script setup>
import { ref } from 'vue';
const msg = ref('xianqitian')
const rawHtml = ref('<h1>123</h1>')
const title = ref('title')
const object = ref({
id : '110',
class : 'box'
})
const number = ref(100)//定义数字
const ok = ref(false)//布尔类型
const works = ref('hello vue3')//定义字符串
const isshow = ref(true)//布尔类型
const handleClick = function(){//改变布尔类型的函数
isshow.value = !isshow.value
}
const handleKeyup = function(e){//监测文本框输入的内容到控制台
console.log(e.target.value)
}
</script>
<template>
<div>
{{msg}}
</div>
<div>
{{ rawHtml }}
</div>
<div v-html="rawHtml"></div><!--文本以标签解析显示-->
<div v-bind:title="title">标题1</div><!--绑定title属性的值-->
<div v-bind = "object" > 标题2 </div><!--绑定对象属性到标签属性里-->
<div>
{{number + 1}}<!--可以运算-->
{{ ok ? 'yes' : 'no'}}<!--三元运算符,用于判断显示什么值-->
{{works.split('').reverse().join('')}}<!--字符串转字符,反转,再转字符串-->
</div>
<div v-if="isshow">
v-if显示了
</div>
<div>
<button v-on:click="handleClick">点击显示开关</button><!--@click等价于v-on:click-->
</div>
<div>
<input type="text" v-on:keyup.enter="handleKeyup"><!--监测文本框输入的内容-->
</div>
</template>
<style lang="css">
</style>
语法例:v-on:keyup.enter=“handleKeyup”,监听文本框输入,加上.enter是回车后运行handleKeyup方法。
4、响应式基础
ref与reactive,两种定义属性的方法
<script setup>
import { ref, reactive } from 'vue'
const state = reactive({ count : 0 })//reactive定义一定要给对象
const count = ref(0)
const handleCountAdd = function(){//定义自增方法
state.count ++
console.log(state)
}
const Add = function(){//定义自增方法
count.value ++
console.log(count)
}
</script>
<template>
<div>
<button @click="handleCountAdd">{{state.count}}</button><!--自己定义了哪个值就是哪个-->
</div>
<div>
{{count}}<!--自动解析ref里的value值-->
</div>
<div>
<button @click="Add">{{count}}</button>
</div>
</template>
<style lang="css">
</style>
5、计算属性(computed)
computed属性方法:
<script setup>
import { ref , computed } from 'vue';
const count = ref(1)//ref在script里操作数据要加上.value(重要)
const title = ref( ' hello')
const handleclick = function(){
count.value++
}
const doubleCount = computed(function(){//推荐用这种方式,点击不会打印
console.log("hello")
//计算属性会基于缓存
return count.value * 2
})
// const doubleCount = function(){//用函数的方法技术数据,程序在运行其他的程序时,会额外的执行下面代码块的代码
// console.log("hello")
// return count.value * 2
// }
const handleChangeTitle = function(){
title.value = "world"
}
</script>
<template>
<div>
{{count}}
</div>
<div>
{{doubleCount}}
</div>
<!-- <div>
{{doubleCount()}}
</div> -->
<div>
<button @click="handleclick">点击</button>
</div>
<div>
{{title}}
</div>
<div>
<button @click="handleChangeTitle">改变值</button>
</div>
</template>
<style lang="css">
</style>
6、class&style绑定
<script setup>
import { ref } from 'vue';
const hasColora = ref(true)
const italic = ref('italic')
const ui = ref('underline')//定于属性样式
const handleChange = function(){
hasColora.value = ! hasColora.value
}
</script>
<template> <!-- 既有c的属性,也有italic,a和b的属性-->
<div class="c" v-bind:class="[ italic , { a: hasColora , b : true } ]"> <!-- 可以判断样式是否显示,可以直接使用变量或者是直接使用布尔值-->
<p :style="{'textDecoration' : ui }">hello Vue3</p><!-- 引用script里定义的属性值,这样就可以控制样式的显示了-->
</div>
<div>
<button @click="handleChange"> change </button>
</div>
</template>
<style lang="css">
.a {
color: red;
}
.b {
font-size: 50px;
}
.c {
background-color: aqua;
}
.italic {
width: 200px;
height: 200px;
}
</style>
例子:example.vue
响应式的样式加载
<script setup>
import { ref } from 'vue';
const list = ref(['line1',' line2', 'line3'])
const curentIndex = ref(0)
const handleClick = function(index){//修改显示curentIndex为哪个下标
curentIndex.value = index
}
</script>
<template>
<ul>
<!--index == curentIndex返回一个布尔值,决定是否显示该active的样式-->
<li
v-for = "item,index in list "
:class="{active : index == curentIndex}"
@click="handleClick(index)"><!--传入元素的index,进行修改-->
{{item}}
</li>
</ul>
</template>
<style lang="css">
.active {
color: red;
font-size: 50px;
}
</style>
7、条件渲染(v-if,v-else-if,v-else)
1.v-if,v-else-if,v-else用法,条件为ture就显示。
2.两两元素互斥,使用标签包裹起来,再用v-if标签。
<script setup>
import { V_ON_WITH_KEYS } from '@vue/compiler-dom';
import { ref } from 'vue';
const isShow = ref(true)
const grade = ref(65)
const handleChange = function(){
isShow.value = !isShow.value
}
const handleKeyup = function(e){
grade.value = e.target.value
}
</script>
<template>
<div v-if="isShow">
hello
</div>
<div>
<button @click="handleChange">change Show</button>
</div>
<div v-if="(grade >= 60)">
A
</div>
<div v-else-if="(grade < 60 & grade >= 30)">
B
</div>
<div v-else="(grade < 30)">
C
</div>
<div>
<input type="text" v-on:keyup.enter="handleKeyup"><!--监测文本框输入的内容,加上.enter按回车触发函数-->
</div>
<div>
<template v-if="isShow">
<p>hello</p>
<p>!!!</p>
</template>
<template v-else>
<p>vue3</p>
<p>...</p>
</template>
</div>
</template>
<style lang="css">
</style>
8、列表渲染(v-if,v-for)
VScode里安装Vue Language Features (Volar)插件
v-if,v-for不能同时作用一个标签上。
- 数组与对象的元素遍历展示。
<script setup>
import { ref,reactive } from 'vue';
const list = ref(['苹果','香蕉','橘子','土豆'])
const course = reactive({
title:"Atian学Vue3",
author:'xianqitian',
publishDate:'2020-12-07'
})
</script>
<template>
<ul>
<template v-for="itme,index in list"> <!-- (重要)v-for与v-if不能作用与同一个标签上,所以要分开使用-->
<li v-if="itme!='土豆'"><!-- 遍历数组中的元素,并实现过滤-->
{{index}}-{{itme}}
</li>
</template>
</ul>
<ul>
<li v-for="c,k,i in course"> <!--遍历对象中的属性: i是下标,k是属性名,c是属性值 -->
{{i}}-{{k}} : {{c}}
</li>
</ul>
</template>
<style lang="css">
</style>
9、事件处理($event)
简写
-
v-bind 对应 :
后面跟上标签的属性::style=“{‘textDecoration’ : ui }”
主要用于ref定义的属性能用于标签属性 -
v-on 对应 @
主要用于事件触发调用函数
重要
触发两个函数运行,vue3特有的
<script setup>
import { ref } from 'vue';
const count = ref(0)
const handleClick = function(number){
count.value+=number
}
const handleInput = function(number,event){
console.log(number)
console.log(event.target.value)//event.target.value为获取到输入框的值
}
const handle1 = () =>{
console.log('handle1')
}
const handle2 = () =>{
console.log('handle2')
}
</script>
<template>
<div>
{{count}}
</div>
<div>
<button @click="handleClick(100)">增加</button>
</div>
<div>
<input type="text" @input="handleInput(100,$event)"> <!-- 事件处理,$event特殊写法,使得可以传自己定的参数也可以传原本的$event事件 -->
</div>
<div>
<button @click="(event)=>handleClick(100)">点击1</button><!--该语法了解即可-->
</div>
<div>
<button @click="handle1(),handle2()">点击2</button><!--vue3特有的语法,可以同时调用两个函数,并且要加()运行一下,重要的括号不能忘了-->
</div>
</template>
<style lang="css">
</style>
10、表单输入绑定(v-model)
1.双向绑定(原始的)
很麻烦
<script setup>
import { ref } from 'vue';
const textValue = ref('a')
const handleInput = (e)=>{
textValue.value = e.target.value
}
</script>
<template>
<div>
<p>{{textValue}}</p>
<input type="text" :value="textValue" @input="handleInput($event)">
</div>
</template>
<style lang="css">
</style>
2.语法糖(v-model)
<script setup>
import { ref } from 'vue';
const textValue = ref('a')
// const handleInput = (e)=>{
// textValue.value = e.target.value
// }
const textAreaValue = ref('a')
const checked = ref(true)
const picked = ref('One')
const favorites = ref([])
//const selectValue = ref('')//下拉单选字符串就行了
const selectValue = ref([])//下拉多选要数组
</script>
<template>
<div>
<p>{{textValue}}</p>
<!-- <input type="text" :value="textValue" @input="handleInput($event)"> -->
<input type="text" v-model="textValue"><!--单行文本框-->
</div>
<div>
<p style="white-space:pre-line">{{textAreaValue}}</p><!--加上这行style="white-space:pre-line"输出打印-->
<textarea v-model="textAreaValue"></textarea><!--多行文本框-->
</div>
<div>
<label for="chb"></label><!--label for是方便用户进行选择的-->
<input id="chb" type="checkbox" v-model="checked">{{checked}}<!--多选框绑定布尔属性的逻辑(v-model)-->
</div>
<div>
{{picked}}<!--选择哪个就是哪个value的值-->
<input type="radio" value="One" v-model="picked">One <!--单选框绑定布尔属性的逻辑(v-model)-->
<input type="radio" value="Two" v-model="picked">Two
</div>
<div>
{{favorites}}
<input type="checkbox" value="篮球" v-model="favorites">篮球<!--多选框绑定数组的逻辑(v-model)-->
<input type="checkbox" value="台球" v-model="favorites">台球
<input type="checkbox" value="羽毛球" v-model="favorites">羽毛球
</div>
<div><!--下拉框(v-model),也是利用v-model绑定属性进行获取value的值-->
{{selectValue}}
<select v-model="selectValue" multiple><!--加上multiple是多选-->
<option value="">请选择</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="深圳">深圳</option>
<option value="广州">广州</option>
</select>
</div>
</template>
<style lang="css">
</style>
11、生命周期函数(onMounted…)
为什么要使用生命周期函数,生命周期函数是什么?
因为dom节点没加载出来,就不能操作dom节点,会有问题。
Vue3提供了钩子函数可以使用
Mounted(加载完的意思)
导入onMounted模块
import { ref, onMounted} from 'vue';
<script setup>
import { ref, onMounted, onBeforeMount, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue';//导入开头小写为函数
const count = ref(0)
let t = null
// setTimeout(()=>{ //定时两秒执行,这种方法会频繁的创建setTimeout函数,会有内存溢出的问题。(不建议使用)
// count.value+=2
// },2000)
//console.log(document.getElementById('a').innerHTML) //获取不到,因为dom节点没有加载出来(所以需要生命周期函数)
t = setTimeout(()=>{
count.value = 2
},1000)
onMounted(()=>{ //dom节点渲染完成后的回调函数
console.log(document.getElementById('a').innerHTML) //放入钩子函数的回调函数里执行,就可以正确的获取到dom的值并输出。
setTimeout(()=>{
count.value = 2
},2000)
})
onBeforeMount(()=>{//dom节点渲染前的回调函数
// console.log(document.getElementById('a').innerHTML)
// 这里可以用作修改之前定义的属性
})
onBeforeUpdate(()=>{
console.log(document.getElementById('a').innerHTML)//改变属性元素,没渲染完dom元素之前执行,自动执行的
})
onUpdated(()=>{
console.log(document.getElementById('a').innerHTML)//渲染完dom后执行的,自动执行的
})
onBeforeUnmount(()=>{//页面卸载之前执行
console.log('onBeforeUnmount')
})
onUnmounted(()=>{//页面卸载之后执行(这里可以做清理函数的作用)
console.log('onUnmounted')
clearTimeout(t)//清理函数
})
</script>
<template>
<div id="a">
{{count}}
</div>
</template>
<style lang="css">
</style>
要想onUnmounted有效果,要在main.js里卸载实列
import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)
const app = createApp(App)
app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序
//卸载组件
setTimeout(()=>{
app.unmount()
},5000)
12、监听器(watchEffect,watch)
类似于:狙击手一枪毙命,不像computed 要返回值。
就偷偷观察,你变我也变。
导入watchEffect,watch
import { ref , watchEffect , computed, watch } from 'vue';
<script setup>
import { ref , watchEffect , computed, watch } from 'vue';
const count = ref(0)
const title = ref('hello')
const doubleCount = computed( () => count.value * 2 )
const handleClick = ()=>{
count.value ++
title.value = "vue3"
}
// watchEffect(()=>{//能监听watchEffect里有的属性变化,代码块里的属性有变化就执行该监听器。(所有都会变化,不精准)
// console.log('count变化了:'+count.value)
// console.log('title变化了:'+title.value)
// })
// watch(//精确的监听页面,值变化,值不变化是不会执行的
// count,//监听的值
// ()=>{//监听的值变化了,就执行以下代码
// console.log('count变化了:'+count.value)
// }
// )
watch(//精确的监听页面,值变化,值不变化是不会执行的(第二种写法)
()=>{
//这里可以写逻辑(一百行逻辑)
console.log('hello vue3!!')
return count.value //监听的值
},
()=>{//监听的值变化了,就执行以下代码
console.log('count变化了:'+count.value)
}
)
</script>
<template>
<div>
{{count}}
{{doubleCount}}
{{title}}
</div>
<div>
<button @click="handleClick">add</button>
</div>
</template>
<style lang="css">
</style>
watch和 watchEffect都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式;
- watch 只追踪明确侦听的源。它不会追踪任何在回调中访问到的东西。另外,仅在响应源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。
- watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式property。这更方便,而且代码往往更简洁,但其响应性依赖关系不那么明确。
13、组件注册
组件允许我们将U划分为独立的、可重用的部分来思考。组件在应用程序中常常被组织成层层嵌套的树状结构:
这和我们嵌套HTML元素的方式类似,Vue实现了自己的组件数据模型,使我们可以在每个组件内封装自定义内容与逻辑。Vue同样也能很好地配合原生Web Component。
1.引入全局组件
先定义组件vue文件。
GlobalComponent.vue
<script setup>
import { ref } from 'vue';
</script>
<template>
<div>
global component
</div>
</template>
<style lang="css">
</style>
2.main.js配置
(重要)app.component(‘GC’,GlobalComponents)//将该页面定义为全局组件
import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)
import GlobalComponents from './componentss/GlobalComponent.vue'
const app = createApp(App)
app.component('GC',GlobalComponents)//将该页面定义为全局组件,GC是自己起的名字
app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序
//卸载组件
// setTimeout(()=>{
// app.unmount()
// },5000)
3.使用组件
<GC></GC><!-- 引入全局组件 -->
<script setup>
import { ref } from 'vue';
</script>
<template>
<div>
<GC></GC><!-- 引入全局组件 -->
</div>
</template>
<style lang="css">
</style>
2.引入局部组件
1.定义Child.vue组件
<script setup>
import { ref } from 'vue';
</script>
<template>
<div>
Child
</div>
</template>
<style lang="css">
</style>
2.导入局部组件
import Child from '../componentss/Child.vue'//导入局部组件
3.引入局部组件
<Child></Child><!-- 引入局部组件 -->
<script setup>
import { ref } from 'vue';
import Child from '../componentss/Child.vue'//导入局部组件
</script>
<template>
<div>
<GC></GC><!-- 引入全局组件 -->
<Child></Child><!-- 引入局部组件 -->
</div>
</template>
<style lang="css">
</style>
14、组件中的数据传递
1.Props(主要是父子主键传递数据)
1.1 父组件传递给子组件(通过绑定属性)
标签上使用(:属性= “XXX” )来向子组件传递数据。
传递会跟着变化
<script setup>
import { ref } from 'vue';
import Child1 from '../componentss/Child1.vue'
import Child2 from '../componentss/Child2.vue'
const count = ref(100)//传递的属性
</script>
<template>
<div>
<Child1 :count="count"></Child1> <!-- 使用:count="count"方式来传递属性 -->
<Child2 :count="count"></Child2> <!-- 使用:count="count"方式来传递属性 -->
</div>
</template>
<style lang="css">
</style>
子组件使用父组件传来的属性:
用defineProps([‘count’])接收
<script setup>
import { ref } from 'vue';
defineProps(['count'])//接收父组件传来的属性
</script>
<template>
<div>
Child1-{{count}}<!--使用属性-->
</div>
</template>
<style lang="css">
</style>
1.2 子组件传递给父组件(通过调用函数传值)
1.父组件里先定义自己的事件:@my-event=“handleMyEvent”
const handleMyEvent = (msg)=>{//要子组件能调用这个方法,父组件才能获取到值。
console.log(msg.value)//这里拿到子组件传的值
}
<Child2 :count="count" @my-event="handleMyEvent"></Child2> <!-- 自定义事件:@my-event="handleMyEvent"用来使得子组件能向父组件传递参数 -->
2.然后让子组件调用该事件函数(重要const emit = defineEmits([‘my-event’]))
const emit = defineEmits(['my-event'])//获取到父组件自己定义的事件
const title = ref('hello VUE3')
onMounted(()=>{//dom节点渲染完成就执行这个方法
emit('my-event',title)//调用父组件的my-event方法传title过去(重要)
console.log(values.count)//这里属于模板外,所以要变量接收才能调用
})
3.完整代码(如下)
Props.vue
<script setup>
import { ref ,onMounted} from 'vue';
import Child1 from '../componentss/Child1.vue'
import Child2 from '../componentss/Child2.vue'
const count = ref(100)
onMounted(()=>{
setTimeout(()=>{
count.value = 10000
},5000)
})
const handleMyEvent = (msg)=>{//要子组件能调用这个方法,父组件才能获取到值。
console.log(msg.value)//这里拿到子组件传的值
}
</script>
<template>
<div>
<Child1 :count="count"></Child1> <!-- 使用:count="count"方式来传递属性 -->
<Child2 :count="count" @my-event="handleMyEvent"></Child2> <!-- 自定义事件:@my-event="handleMyEvent"用来使得子组件能向父组件传递参数 -->
</div>
</template>
<style lang="css">
</style>
Child2.vue
<script setup>
import { ref, onMounted} from 'vue';
const values = defineProps(['count'])//模板直接使用不需要变量接收({{count}}),模板以外要变量接收才能使用
const emit = defineEmits(['my-event'])
const title = ref('hello VUE3')
onMounted(()=>{//dom节点渲染完成就执行这个方法
emit('my-event',title)//调用父组件的my-event方法传title过去(重要)
console.log(values.count)//这里属于模板外,所以要变量接收才能调用
})
</script>
<template>
<div>
Child2-{{count}}
</div>
</template>
<style lang="css">
</style>
15、事件(defineEmits)
1.子组件向父组件传数据的第二种方法
定义component-event.vue(v-model:t=“title”)定义事件
<script setup>
import { ref } from 'vue';
import Chile from '../componentss/Child.vue'
const title = ref('hello')
</script>
<template>
{{title}}
<Chile v-model:t="title"></Chile><!-- 这里定义t事件,子组件调用传参 -->
</template>
<style lang="css">
</style>
2.子组件调用事件传参(const emit = defineEmits([‘update:t’]), emit( ‘update:t’,title.value ))
<script setup>
import { onMounted, ref } from 'vue';
const title = ref('VUE3')
const emit = defineEmits(['update:t'])//获取到父组件的子组件标签上的定义事件。(注意单词很容易写错,update:固定写法)
onMounted(()=>{
emit( 'update:t',title.value )//触发事件,传参给父组件。
})
</script>
<template>
<div>
Child
</div>
</template>
<style lang="css">
</style>
16、透传:attributes
1.transparent.vue
<script setup>
import { ref } from 'vue';
import Child3 from '../componentss/Child3.vue'//调用局部组件
</script>
<template>
<div>
<Child3 title="hello" class="a"></Child3> <!-- 这样子写属性会自动添加到子组件上 -->
</div>
</template>
<style lang="css">
.a {
color: red;
}
</style>
2.Child3.vue
<script>
export default {//阻断透传
inheritAttrs: false
}
</script>
<script setup>
import { ref ,useAttrs} from 'vue';
const attrs = useAttrs()
console.log(attrs)//获取属性集合,父组件传递的属性
</script>
<template>
<div id="child"> Child3</div> <!-- 注意带上div -->
</template>
<style lang="css">
</style>
17、插槽(v-slot:XXX)
1.v-slot:XXX只能用于父组件的template标签上(具名插槽)
<!--可以只写v-slot:line2,不获取子组件传来的值也可以-->
<template v-slot:line2> <!-- v-slot:只能作用到template标签上 -->
<div>VUE3</div><!--{{XXXX}}可以传递自己的常量-->
</template>
2.slot标签用于子组件里
<slot name="line2"></slot><!--name="line2"标识是哪个插槽-->
作用域插槽(v-slot:default默认显示)
<template v-slot:default="data01"><!--data就是子组件传过来的值(是一个数组)-->
<div>{{hello}} slot {{data01.mark}}--{{data01.hello}}</div> <!--{{data01.mark}}--{{data01.hello}}获取子组件传来的值,并用于标签显示-->
</template>
3.slot.vue
<script setup>
import { ref } from 'vue';
import Child4 from '../componentss/Child4.vue';
const hello = ref('hello')
</script>
<template>
<Child4>
<!--可以直接v-slot:default="{mark,hello}"解析出传过来的属性,然后直接使用-->
<template v-slot:default="data01"><!--data就是子组件传过来的值(是一个数组)-->
<div>{{hello}} slot {{data01.mark}}--{{data01.hello}}</div> <!--{{data01.mark}}--{{data01.hello}}获取子组件传来的值,并用于标签显示-->
</template>
<!--可以只写v-slot:line2,不获取子组件传来的值也可以-->
<template v-slot:line2="data02"> <!-- v-slot:只能作用到template标签上 -->
<div>{{hello}} VUE3--{{data02.vue3}}</div><!--{{hello}}可以传递自己的常量-->
</template>
</Child4>
</template>
<style lang="css">
</style>
4.Chlid4.vue
<script setup>
import { ref } from 'vue';
const mark = ref('!!!')
</script>
<template>
<div>
<!--标签里的hello为默认值,如果主组件没有定义就显示这个。:mark冒号解析上面script定义的值,相当于是v-bind-->
<!--也可以定义普通的属性用来传递(hello="hello")-->
<slot :mark="mark" hello="hello">hello</slot>
<slot name="line2" vue3="vue3"></slot><!--name="line2"标识是哪个插槽-->
</div>
</template>
<style lang="css">
</style>
使用图例:
简写:v-slot = ‘#’(重要)
18、依赖注入(任何主键中数据传递的方法)
- vue中解构provide和inject
1.使用:provide函数定义title属性,值为hello。用于孙组件获取值
provide('title','hello')//使用provide函数定义title属性,值为hello。用于孙组件获取值
2.使用:inject(‘title’)注入值,来使用。(可以在任何的组件里使用)
const title = inject('title')
3.inject-provide.vue
<script setup>
import { onMounted, provide, ref } from 'vue';
import Child5 from '../componentss/Child5.vue'
import Child6 from '../componentss/Child6.vue'
const title = ref('hello2')
provide('title',title)//使用provide函数定义title属性,值为hello。用于孙组件获取值
provide('count','100')//是响应式的,非常方便。
onMounted(()=>{//是响应式的,非常方便。
setTimeout(() => {
title.value = 'VUE3'
}, 2000);
})
</script>
<template>
<div>
<Child5></Child5>
<Child6></Child6>
</div>
</template>
<style lang="css">
</style>
4.Chlid5和Child6
<script setup>
import { ref,inject } from 'vue';
const title = inject('title')//属性注入
</script>
<template>
<div>Child5--{{title}}</div>
</template>
<style lang="css">
</style>
<script setup>
import { ref ,inject} from 'vue';
import Grandson from './Grandson.vue';
const title = inject('title')//属性注入
</script>
<template>
<div>{{title}}--Child6</div>
<Grandson></Grandson>
</template>
<style lang="css">
</style>
5.Grandson.vue
<script setup>
import { ref,inject} from 'vue';//inject注入
const title = inject('title')//属性注入
const count = inject('count')
</script>
<template>
<div>{{title}}--Grandson--{{count}}</div>
</template>
<style lang="css">
</style>
19、组合式函数(模块化的拆分)
1.Demo.vue
<script setup>
import useTitle from './useTitle'//拆分模块,导入不同功能的模块
import useCount from './useCount'//拆分模块,导入不同功能的模块
const {count,handleClick} = useCount()//解析出两个相当于是模块
useTitle(count)
</script>
<template>
<div>
{{count}}
<button @click="handleClick">add</button>
</div>
</template>
<style lang="css">
</style>
2.useTitle.js
import {onMounted,onUpdated} from 'vue'
const useTitle = (title)=>{
onMounted(()=>{
document.title = title.value
})
onUpdated(()=>{//页面数据修改之后触发!!
document.title = title.value
})
}
export default useTitle // 将函数暴露出去
3.useCount.js
import { onMounted, onUpdated, ref } from 'vue';
const useCount = () => {
const count = ref(0)
const handleClick = function(){
count.value++
}
return {count,handleClick}//有属性的对象,要返回属性跟函数
}
export default useCount // 将函数暴露出去
20、自定义指令
1.定义指令的js文件
const focus = {
mounted: (el) => el.focus()//自动获取焦点的指令
}
export default focus
2.在main.js里将一个自定义指令全局注册到应用层级也是一种常见的做法
- app.directive(‘focus’,focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法
import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)
import GlobalComponents from './componentss/GlobalComponent.vue'
import focus from './instructions/focus.js'
const app = createApp(App)
app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法
app.component('GC',GlobalComponents)//将该页面定义为全局组件
app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序
//卸载组件
// setTimeout(()=>{
// app.unmount()
// },5000)
3.使用自己定义的指令
- < input v-focus/> 使用自己定义的指令
<script setup>
import { ref} from 'vue';
</script>
<template>
<div>
<input v-focus/><!-- 使用自己定义的指令 -->
</div>
</template>
<style lang="css">
</style>
21、插件
插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。
1.定义自己的插件
import Demo from '../components/Demo.vue'
export default {
install(app,options){
// 配置此应用
//插件没有严格定义的使用范围,但是插件发挥作用的常见场景主要包括以下几种:
//1.通过 app.component() 和 app.directive() 注册一到多个全局组件或自定义指令。
app.component('Demo',Demo)//注册了全局组件
//2.通过 app.provide() 使一个资源可被注入进整个应用。
//3.向 app.config.globalProperties 中添加一些全局实例属性或方法
//4.一个可能上述三种都包含了的功能库 (例如 vue-router)。
app.mixin({
mounted(){
console.log(options)//输出hello
}
})
}
}
2.main.js中加载自己定义的插件
import myPlugin from './plugin/myPlugin'
app.use(myPlugin,'myPlugin-test')//定义自己的插件:第一个参数是插件,第二个参数是传递的值
import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)
import GlobalComponents from './componentss/GlobalComponent.vue'
import focus from './instructions/focus.js'
import myPlugin from './plugin/myPlugin'
const app = createApp(App)
app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法
app.component('GC',GlobalComponents)//将该页面定义为全局组件
app.use(myPlugin,'myPlugin-test')//定义自己的插件:第一个参数是插件,第二个参数是传递的值
app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序
//卸载组件
// setTimeout(()=>{
// app.unmount()
// },5000)
3.使用自己定义插件里注册的全局组件
<script setup>
import { ref } from 'vue';
</script>
<template>
<Demo></Demo>
</template>
<style lang="css">
</style>
三、路由(vueRouter4)
// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }
// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
]
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)
app.mount('#app')
// 现在,应用已经启动了!s
1、vue3项目流程
1.index.html引入main.js文件定义 < div id=“app” >< /div >用来挂载vue将应用实例的根组件挂载在提供的 DOM 元素上。
<body>
<div id="app"></div>
<script type="module" src="./src/main.js"></script>
</body>
2.main.js导入各种组件,加载渲染。
import { createApp} from 'vue'
import Router from './router/router'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)
import GlobalComponents from './componentss/GlobalComponent.vue'
import focus from './instructions/focus.js'
// import myPlugin from './plugin/myPlugin'//导入自定义插件
const app = createApp(App)
app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法
app.component('GC',GlobalComponents)//将该页面定义为全局组件
//定义自己的插件:第一个参数是插件,第二个参数是传递的值
//app.use(myPlugin,'myPlugin-test')
app.use(Router)//注册页面路由
app.use(Button)
app.mount('#app')//mount方法,将应用实例的根组件挂载在提供的 DOM 元素上#app对应index.html的<div id="app"></div>。(要注意代码放置的先后顺序)
//卸载组件
// setTimeout(()=>{
// app.unmount()
// },5000)
3.App.vue:main.js文件导入了App.vue,使用const app = createApp(App)来创建vue单独的入口。
<script setup>
// import Demo from '../src/components/Demo.vue'
// import Demo from '../src/components/Demo2.vue'
// import Demo from '../src/components/Demo3.vue'
// import Demo from '../src/components/Demo4.vue'
// import Demo from '../src/components/Demo5.vue'
// import Demo from '../src/components/Example.vue'
// import Demo from '../src/components/Demo6.vue'
// import Demo from '../src/components/Demo7.vue'
// import Demo from '../src/components/Event.vue'
// import Demo from '../src/components/Form.vue'
// import Demo from '../src/components/LifeCycle.vue'
// import Demo from '../src/components/watcher.vue'
// import Demo from '../src/components/components.vue'
// import Demo from '../src/components/Props.vue'
// import Demo from '../src/components/component-event.vue'
// import Demo from '../src/components/transparent.vue'
// import Demo from '../src/components/slot.vue'
// import Demo from '../src/components/inject-provide.vue'
// import Demo from './composition-functions/Demo.vue'
// import Demo from './instructions/Demo.vue'
// import Demo from './plugin/Demo.vue'
import Demo from './router/Demo.vue'
</script>
<template>
<Demo></Demo>
</template>
<style lang="css">
</style>
4.定义router.js路由文件。
import { createRouter,createWebHistory } from "vue-router";//载入createRouter,createWebHistory模块
import Home from './Home.vue'//导入需要跳转的vue页面
import About from './About.vue'//导入需要跳转的vue页面
const routes = [
{
path:'/',
redirect: '/home'//重定向页面
},
{
path:'/home',
component: Home//跳转的组件
},
{
path:'/about',
component: About//跳转的组件
}
]
const router = createRouter({//创建router函数,创建相关的参数。
routes,
history: createWebHistory()
})
export default router //暴露router函数,方便其他文件调用。
5.新建Home.vue和About.vue
<script setup>
</script>
<template>
<div>Home</div>
</template>
<style lang="css">
</style>
<script setup>
</script>
<template>
<div>Home</div>
</template>
<style lang="css">
</style>
四、pinia(状态管理工具)
1.安装pinia
# 或者使用 npm
npm install pinia
2.在vue3的main.js里载入pinia
import { createPinia } from 'pinia'
app.use(createPinia())
import { createApp} from 'vue'
import Router from './router/router'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)
import ElementPlus from 'element-plus'//导入element-plus
import 'element-plus/dist/index.css'//导入element-plus
import {createPinia} from 'pinia'//导入pinia类似于vuex的工具
import GlobalComponents from './componentss/GlobalComponent.vue'//将该页面定义为全局组件
import focus from './instructions/focus.js'//将一个自定义指令全局注册到应用层级也是一种常见的做法
// import myPlugin from './plugin/myPlugin'//导入自定义插件
const app = createApp(App)
app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法
app.component('GC',GlobalComponents)//将该页面定义为全局组件
app.use(createPinia())//导入pinia类似于vuex的工具,不要忘记带括号,执行一下。
//定义自己的插件:第一个参数是插件,第二个参数是传递的值
//app.use(myPlugin,'myPlugin-test')
app.use(Router)//注册页面路由
app.use(ElementPlus)//注册element-plus
app.use(Button)
app.mount('#app')//mount方法,将应用实例的根组件挂载在提供的 DOM 元素上#app对应index.html的<div id="app"></div>。(要注意代码放置的先后顺序)
//卸载组件
// setTimeout(()=>{
// app.unmount()
// },5000)
3.使用pinia
https://pinia.web3doc.top/core-concepts/actions.html
1、创建store目录,目录下新建各种XXXXStore.js管理状态。(可以定义多个管理不同的状态)
例子:counterStore.js
import { defineStore } from 'pinia'
const useCounterStore = defineStore('StoreName',{//StoreName是自己定义的,defineStore方法返回的是函数
state : ()=>{//定义state函数,并添加返回值
return {
count : 100
}
},
actions:{//actions是对象,里面可以定义很多的函数(重要:可以使用异步函数,页面渲染完用vue里的onMounted方法调用后端接口)
add(){
this.count++//用this关键字来访问上述定义的值
}
},
getters:{//定义计算state里的方法
tolalPrice(){
return this.count + 100
}
}
})
export default useCounterStore
Demo.vue
<script setup>
import {storeToRefs} from 'pinia' //解构成ref
import useCounterStore from '@/store/counterStore'
import { onMounted } from 'vue';
const counterStore = useCounterStore()//用一个变量来接收useCounterStore暴露出的属性和方法
const {count} = storeToRefs(counterStore)//可以直接使用,也可以解构成ref来用。(方法解构不了)
const add = counterStore.add//解构,解不解都行,counterStore.add直接用也行
console.log(counterStore)//输出的是proxy的对象
</script>
<template>
<div>
{{count}}<!--使用counterStore里的定义的count值-->
</div>
<div>
<button @click='add()'>add</button><!--使用counterStore里的定义的add方法-->
</div>
<div>
{{counterStore.tolalPrice}}<!--调用counterStore里getters里定义计算属性的值-->
</div>
</template>
<style lang="css">
</style>