一、前端环境搭建
参考地址:
二、基础要点
2.1 setup 语法糖
2.1.1 使用前
setup内定义的变量和方法需要return才能使用
<script>
export default{
setup(){
const mes = "this is message"
const loadMes = ()=>{
console.log(mes)
}
console.log("set up ")
return{
mes,
loadMes
}
},
beforeCreate(){
console.log("beforeCreate")
}
}
</script>
<template>
<div>
{{ mes }}
<button @click="loadMes">click me</button>
</div>
</template>
2.1.2 使用后
不需要return就能试用变量或者方法了
<script setup>
const mes = "this is message"
const loadMes = ()=>{
console.log(mes)
}
</script>
<template>
<div>
{{ mes }}
<button @click="loadMes">click me</button>
</div>
</template>
2.2 响应式数据
2.2.1 reactive
<script setup>
// 1. 导入函数
import { reactive } from 'vue';
// 2. 执行函数,传入一个对象类型的参数,变量接受
const state = reactive({
count : 0
})
const setCount = () =>{
state.count++
}
</script>
<template>
<div>
{{ count }}
<button @click="setCount">{{ state.count }}</button>
</div>
</template>
2.2.2 ref
<script setup>
// 1. 导入函数
import { ref } from 'vue';
// 2. 执行函数,传入参数【简单类型 + 对象类型】,变量接受
const count = ref(0)
const setCount = () =>{
// 脚本区域修改ref产生的相应对象数据,必须通过.value属性
count.value++
}
</script>
<template>
<div>
<button @click="setCount">{{ count }}</button>
</div>
</template>
2.2.3 比较:reactive vs ref
- reactive 不能处理简单类型的数据
- ref参数类型支持更好但是必须通过.value访问修改
- ref内部的是实现依赖于reactive函数
2.3 计算属性
2.3.1 简单案例
从数组中筛选出数值大于2的元素,并在3秒后追加9,10到数组中
<script setup>
import { ref } from 'vue';
// 原始响应数组
const list = ref([1,2,3,4,5,6,7])
// 1.导入conputrd
import { computed } from 'vue';
// 2.执行函数,return计算之后的值,变量接受
const res = computed(()=>{
return list.value.filter(item=>item>2)
})
setTimeout(()=>{
list.value.push(9,10)
},3000)
</script>
<template>
<div>原始响应数组{{ list }}</div>
<div>计算后的数组为{{ res }}</div>
</template>
2.3.2 最佳实践
- 计算属性不应该有副作用(比如异步请求、修改dom)
- 避免直接修改计算属性的值(计算属性应该是只读的)
2.4 watch
2.4.1 元素监听
2.4.1.1 单个元素
<script setup>
// 1.导入watch
import { ref,watch } from 'vue';
const count = ref(0)
// 2.调用watch 监听变化
// ref不许要添加.value
watch(count,(newValue,oldValue) =>{
console.log("count发生了变化",oldValue,newValue)
})
const setCount = ()=>{
count.value++
}
</script>
<template>
<button @click="setCount">+{{ count }}</button>
</template>
2.4.1.2 多个元素
<script setup>
// 1.导入watch
import { ref,watch } from 'vue';
const count = ref(0)
const name = ref("cp")
const setCount = ()=>{
count.value++
}
const changName = () =>{
name.value = "pc"
}
// 2.调用watch 监听变化
// ref需要添加.value
watch([count,name]
,(
[newCount,newName],
[oldCount,oldName]
) =>{
console.log("count发生了变化",[newCount,newName], [oldCount,oldName])
})
</script>
<template>
<button @click="setCount">+{{ count }}</button>
<button @click="changName">+{{ name }}</button>
</template>
2.4.2 常用参数
2.4.2.1 immediate
在创建时立即触发回调
watch(count,(newValue,oldValue) =>{
console.log("count发生了变化",oldValue,newValue)
},{
immediate:true
})
2.4.2.2 deep
默认watch监听的ref对象默认是浅层监听的,
直接修改嵌套对象属性不会触发回调执行,需要开启deep属性
<script setup>
import { ref,watch } from 'vue';
const state = ref({count:0})
const setCount = ()=>{
//直接修改count
state.value.count++
}
watch(state,() =>{
console.log("count发生了变化")
})
</script>
<template>
<button @click="setCount">+{{ state.count }}</button>
</template>
添加 deep:true 后,直接修改对象的属性将会触发监听事件
2.4.2.3 精确监听
若有多个元素,只想深度监听其中某一个,可选择精确监听
只有点击 age 才会触发监听事件
watch(
() => state.value.age,
() => {
console.log("数值变换了")
}
)
2.5 生命周期
2.5.1 简单案例
** mounted**
若存在多个生命周期函数,则按照定义顺序执行
2.6 父子通信
2.6.1 父传子
2.6.1.1 基础案例
父
<script setup>
// set语法糖下局部组件无需注册直接可以使用
import son from "./Son.vue"
</script>
<template>
<div class="father">
<h2>父组件fa</h2>
<son message="fa send message"></son>
</div>
</template>
子
<script setup>
const props = defineProps({
message:String
})
console.log(props)
</script>
<template>
<div class="son">
<h3>子组件son</h3>
<div>
父组件传入的数据_{{message}}
</div>
</div>
</template>
页面
2.6.1.2 传递响应式数据
2.6.2 子传父
父
<script setup>
import son from "./Son.vue"
import {ref} from "vue"
const get = (msg) =>{
console.log(msg)
}
</script>
<template>
<son @send-msg="get"></son>
</template>
子
<script setup>
const emit = defineEmits(['sendMsg'])
const send = ()=>{
emit('sendMsg','this is son msg')
}
</script>
<template>
<button @click="send">send</button>
</template>
页面
2.6.3 总结
2.7 ref模板引用
2.7.1 基础用法
主页面
<script setup>
import test from "./Test.vue"
import {onMounted, ref} from "vue"
// 调用ref函数 -> ref 对象
const h1Ref = ref(null)
const testRef = ref(null)
// 组件挂载完毕后才能获取
onMounted(()=>{
console.log(h1Ref.value)
console.log(testRef.value)
})
</script>
<template>
<h1 ref="h1Ref">我是h1</h1>
<test ref="testRef"></test>
</template>
组件页面
<script setup>
import { ref } from 'vue';
const name = ref("test name")
const setName = ()=>{
name.value = "test new name"
}
defineExpose({
name,setName
})
</script>
<template>
<h3>我是test组件</h3>
</template>
页面
2.7.2 defineExpose
若想获取子组件的属性以及方法,可在子组件内使用defineExpose
2.8 provide 和 inject
- 顶层组件通过provide提供数据
- 底层组件通过inject组件获取数据
2.8.1 简单案例
top.vue
<script setup>
import {onMounted, provide, ref} from "vue"
import mid from "./Mid.vue"
// 顶层组件提供数据
provide("top","from top")
</script>
<template>
<div class="top">
顶层组件
<mid></mid>
</div>
</template>
<style scoped>
.top{
margin-left: 20px;
}
</style>
mid.vue
<script setup>
import baseOne from "./Base.vue"
</script>
<template>
<div class="mid">
中间组件
<baseOne></baseOne>
</div>
</template>
<style scoped>
.mid {
margin-left: 40px;
}
</style>
base.vue
<script setup>
import { inject, ref } from 'vue';
// 接受数据
const fromTop = inject("top")
</script>
<template>
<div class = "base">
底层组件
<div>
来自顶层组件的数据为{{ fromTop }}
</div>
<div>
来自顶层组件的响应式数据为
</div>
</div>
</template>
<style scoped>
.base{
margin-left: 60px;
}
</style>
视图
2.8.2 传递响应式数据
2.8.3 跨层传递方法
2.8.4 总结
三、 进阶要点
3.1 Pinia
3.1.1 简单使用
3.1.1.1 依赖下载
控制台输入npm install pinia
3.1.1.2 注册pinia
import './assets/main.css'
import { createApp } from 'vue'
import App from './Top.vue'
// 1.导入createPinia
import { createPinia } from 'pinia'
// 2.执行方法得到实例
const pinia = createPinia()
// 把pinia 实例加入app应用中
createApp(App)
.use(pinia)
.mount('#app')
3.1.1.3 创建store
// 导入一个方法 defineStore
import {defineStore} from "pinia"
import { ref } from "vue"
export const useCounterStore = defineStore('counter',()=>{
// 定义数据(state)
const count = ref(0)
// 定义修改数据的方法(action 同步+异步)
const inc = ()=>{
count.value++
}
// 以对象的方式return
return{
count,
inc
}
})
3.1.1.4 调用Store
<script setup>
// 导入方法
import {useCounterStore} from "@/stores/counter"
// 执行方法得到的store实例对象
const counter = useCounterStore()
console.log(counter);
</script>
<template>
<div>{{ counter.count }}</div>
<button @click="counter.inc">click me</button>
</template>
点击按钮后可如期增长数字
3.1.2 getters 实现计算属性
3.1.3 action 实现异步
3.1.3.1 修改store
// 导入一个方法 defineStore
import {defineStore} from "pinia"
import { computed, ref } from "vue"
import axios from 'axios'
export const useCounterStore = defineStore('counter',()=>{
// 定义数据(state)
const count = ref(0)
// 定义修改数据的方法(action 同步+异步)
const inc = ()=>{
count.value++
}
// getter 定义 => 计算属性
const doublueCount = computed(()=>count.value * 2)
// 定义异步action
const list =ref([])
const getList = async () =>{
const res = await axios.get("http://geek.itheima.net/v1_0/channels")
list.value = res.data.data.channels
}
// 以对象的方式return
return{
count,
inc,
doublueCount,
list,
getList
}
})
3.1.3.2 异步调用
<script setup>
// 导入方法
import {useCounterStore} from "@/stores/counter"
import { onMounted } from "vue";
// 执行方法得到的store实例对象
const counter = useCounterStore()
console.log(counter);
onMounted(()=>{
counter.getList()
})
</script>
<template>
<button @click="counter.inc">click me</button>
<div>{{ counter.count }}</div>
<div>{{ counter.doublueCount }}</div>
<ul>
<li v-for="item in counter.list" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
3.1.4 storeToRefs
3.1.4.1 解构数值
3.1.4.2 解构方法
3.1.5 调试
3.2 router
3.2.1 依赖下载
控制台输入npm install vue-router
3.2.2 路由注册
在 main.js 中添加路由信息
3.2.3 编写路由
主页默认重定向到login页面,并定义login页面相关路由信息
import { createRouter, createWebHashHistory } from "vue-router"
import Login from "../views/Login.vue"
// 定义路由
const routers = [{
path:"/",
redirect:"/Login"
},{
path:"/Login",
name:"Login",
component:Login
}]
// 创建router实例
const router = createRouter({
history:createWebHashHistory(),
routes:routers
})
// 导出router实例
export default router