声明:这只是我个人的学习笔记(黑马),供以后复习用 。一天学一点,随时学随时更新。明天会更好的!
这里只给代码,不给运行结果,看不出来代码的作用我也该进厂了。。。。。
Day1 使用create-vue创建项目。
1.检查版本。
node -v
2.创建项目
npm init vue@latest
可以用这个切回国内镜像源
npm config set registry https://registry.npmmirror.com
3. 安装依赖,启动项目
npm install
npm run dev
4.1写法
原始复杂写法setup写法:必须return
<!-- 开关:写组合式组件 -->
<script>
export default {
setup() {
console.log('setup')
const message = 'hello world'
const logMessage = () => {
console.log(message)
}
return {//只有return返回一个对象,对象中的属性和方法,都可以在模板中使用
message,
logMessage,
}
},
beforeCreate() {
console.log('beforeCreate')
},
}
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
{
{ message }}
<button @click="logMessage">log</button>
</div>
</template>
<style scoped></style>
简单的语法糖写法
<script setup>
const message = 'hello world'
const logMessage = () => {
console.log(message)
}
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
{
{ message }}
<button @click="logMessage">log</button>
</div>
</template>
<style scoped></style>
注:1.setup选项在beforeCreate钩子之前自动执行
2.setup中的this不指向组件实例了,指向undefined
4.2 函数调用返回响应式数据
reactive()接受对象类型数据的参数传入并返回一个响应式的对象
<script setup>
// 1.导入函数
import { reactive } from 'vue'
// 2.执行函数 传入一个对象类型的函数 变量接受
const state = reactive({
count: 0
})
const setCount = () => {
state.count++
}
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
<button @click='setCount'>
{
{ state.count }}
</button>
</div>
</template>
<style scoped></style>
ref()接受简单类型或对象类型数据的参数传入并返回一个响应式的对象
脚本区域修改ref的响应式数据 必须通过value属性
<script setup>
// // 1.导入函数
// import { reactive } from 'vue'
// // 2.执行函数 传入一个对象类型的函数 变量接受
// const state = reactive({
// count: 0
// })
// const setCount = () => {
// state.count++
// }
//1.导入ref 函数
import { ref } from 'vue'
//2.执行函数 传入一个简单类型或者对象类型的参数 变量接受
const count = ref(0)
console.log(count)
const setCount = () => {
//脚本区域修改ref的响应式数据 必须通过value属性
count.value++
}
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
<button @click='setCount'>
{
{ count }}
</button>
</div>
</template>
<style scoped></style>
4.3计算属性函数
computed 返回计算后的数据(不应该有副作用)
<script setup>
// 1.导入computed
import { computed } from 'vue'
import { ref } from 'vue'
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])
// 2.使用computed return计算后的值 变量接受
const computedList = computed(() => {
return list.value.filter(item => item > 2)
})
setTimeout(() => {
list.value.push(9, 10)
}, 3000);
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
原始响应式数据-{
{ list }}
</div>
<div>
计算后的响应式数据-{
{ computedList }}
</div>
</template>
<style scoped></style>
4.4watch函数
侦听一个或多个数据的变化,数据变化时执行回调函数(参数:immediate(立即执行),deep(深度侦听))
<script setup>
// import {ref,watch} from 'vue'
// const count = ref(0)
// const setCount = () => {
// count.value++
// }
// //调用watch方法,监听count的变化
// //watch 里面ref对象不需要加.value属性
// watch(count, (newValue, oldValue) => {
// console.log(`count发生了变化,老值是${oldValue},新值是${newValue}`);
// })
import { ref, watch } from 'vue'
const count = ref(0)
const changeCount = () => {
count.value++
}
const name = ref('cp')
const changeName = () => {
name.value = 'pc'
}
watch(
[count,name],
(
[newValue,newName], [oldValue,oldName]
) => {
console.log(`count或者name发生了变化,老值是${[oldValue,oldName]},新值是${[newValue,newName]}`);
})
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
<button @click='changeCount'>修改{
{ count }}</button>
</div>
<div>
<button @click='changeName'>修改{
{ name }}</button>
</div>
</template>
<style scoped></style>
immediate先执行一次回调函数
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const changeCount = () => {
count.value++
}
const name = ref('cp')
const changeName = () => {
name.value = 'pc'
}
watch(
[count, name],
(
[newValue, newName], [oldValue, oldName]
) => {
console.log(`count或者name发生了变化,老值是${[oldValue, oldName]},新值是${[newValue, newName]}`);
}, {
immediate: true//先执行一次回调函数
})
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
<button @click='changeCount'>修改{
{ count }}</button>
</div>
<div>
<button @click='changeName'>修改{
{ name }}</button>
</div>
</template>
<style scoped></style>
deep:通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep
<script setup>
import { ref, watch } from 'vue'
const state = ref({ count: 0, age: 20 })
const changeStateByCount = () => {
state.value.count++
}
watch(state, () => {
console.log('count变化了')
}, {
deep: true//默认监听的整个对象,就是此时age变化,也执行
})
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
<button @click='changeStateByCount'>通过修改</button>
</div>
</template>
<style scoped></style>
精确监听
<script setup>
// import { ref, watch } from 'vue'
// const state = ref({ count: 0, age: 20 })
// const changeStateByCount = () => {
// state.value.count++
// }
// watch(state, () => {
// console.log('count变化了')
// }, {
// deep: true//默认监听的整个对象,就是此时age变化,也执行
// })
import { ref, watch } from 'vue'
const state = ref({
name: 'zhangsan',
age: 20
})
const changeName = () => {
state.value.name = 'lisi'
}
const changeAge = () => {
state.value.age = 30
}
watch(
() => state.value.age,
() => {
console.log('age变化了')
})
//deep有性能损耗 尽量不开启
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
<div> 当前age{
{ state.age }}</div>
<div> 当前name{
{ state.name }}</div>
</div>
<div>
<button @click='changeName'>修改name</button>
<button @click='changeAge'>修改age</button>
</div>
</template>
<style scoped></style>
———————————————————————————————————————————2025.1.16 0时05分 --困了睡觉吧。
4.5生命周期函数
<script setup>
//生命周期函数的使用
import { onMounted } from 'vue'
onMounted(() => {
console.log('组件挂载完成onMounted执行了1')
})
onMounted(() => {
console.log('组件挂载完成onMounted执行了2')
})
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div>
</div>
</template>
<style scoped></style>
4.6组合式API通信
父传子
父组件
<script setup>
//语法糖下局部组件无需注册可以直接使用
import { ref } from 'vue'
import SonCom from './components/son-com.vue'
const count = ref(100)
setTimeout(() => {
count.value = 200
}, 2000)
</script>
<template>
<!-- 不再要求唯一的根元素 -->
<div class='father'>
<h2>父组件App</h2>
<!-- 1.绑定属性 -->
<SonCom :count="count" message='father-message' />
<!-- //响应式数据加“:” -->
</div>
</template>
<style scoped></style>
子组件
<script setup>
//2. 子组件接收数据 defineProps
const props=defineProps({
message: String,
count : Number
})
console.log(props)
</script>
<template>
<div class='son'>
<h3>子组件SON</h3>
<div>
父组件传入的数据-{
{ message }}-{
{ count }}
</div>
</div>
</template>
<style scoped>
</style>
子传父
父组件
<script setup>
import SonCom from './components/son-com.vue'
const getMessage = (msg) => {
console.log(msg)
}
</script>
<template>
<div class='father'>
<h2>父组件App</h2>
<!--1.绑定事件 -->
<SonCom @get-message='getMessage'/>
</div>
</template>
<style scoped></style>
子组件
<script setup>
//2.通过 defineEmits 定义一个自定义事件 ->emit(this.emit)
const emit = defineEmits(['get-message'])
const sendMsg = () => {
emit('get-message', '我是son message')
}
</script>
<template>
<div class='son'>
<div>子组件SON</div>
<button @click='sendMsg'>触发自定义事件</button>
</div>
</template>
<style scoped>
</style>
4.6组合式API-模版引用
父组件
<script setup>
import TestCom from './components/TestCom.vue'
import { onMounted, ref } from 'vue'
//1.调用ref函数-> ref对象
const h1Ref = ref(null)
const comRef = ref(null)
//组件挂载完毕之后才能获取
onMounted(() => {
console.log(h1Ref.value)
console.log(comRef.value);
})
</script>
<template>
<!-- 2.通过ref标识绑定ref对象 -->
<h1 ref="h1Ref">我是dom标签h1</h1>
<TestCom ref='comRef'/>
</template>
<style scoped></style>
子组件
<script setup>
import { ref } from 'vue'
const name = ref('testname')
const setName = () => {
name.value = 'new testname'
}
defineExpose({//子组件的属性和方法通过 defineExpose暴露给父组件使用
name,
setName
})
</script>
<template>
<div>test</div>
</template>
<style scoped></style>
4.7组合式API-provide和inject
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
顶层组件
<script setup>
import RoomMsgItem from './room-msgitem.vue'
import { provide ,ref } from 'vue'
//1.顶层组件提供数据
provide('data-key', '我是顶层组件提供的数据')
//传递响应式数据
const count = ref(0)
provide('count-key', count)
setTimeout(() => {
count.value = 100
}, 2000)
//传递方法(谁的数据谁负责)
const setCount = () => {
count.value++
}
provide('setCount-key', setCount)
</script>
<template>
<!-- 组件嵌套关系 -->
<!-- roompage->roommsgitem->roommsgcomment -->
<div class='page'>
顶层组件
<RoomMsgItem />
</div>
</template>
<style scoped></style>
中间组件
<script setup>
import RoomMsgComment from './room-msg-comment.vue'
</script>
<template>
<div>
中间组件
<room-msg-comment/>
</div>
</template>
<style scoped>
</style>
底层组件
<script setup>
import { inject } from 'vue'
//2.接收数据
const roomDate=inject('data-key')
//接受顶层组件的响应式数据
const countData=inject('count-key')
//接收方法
const setCount=inject('setCount-key')
</script>
<template>
<div class='comment'>
底层组件
<div>
来自顶层组件的数据为:{
{ roomDate }}
</div>
<div>
来自顶层组件的响应式数据:{
{ countData }}
</div>
<button @click='setCount'>修改顶层组件的数据{
{ countData }}</button>
</div>
</template>
<style scoped></style>
5.案例演示
App.vue
<script setup>
import { onMounted,ref } from 'vue'
import Edit from './components/Edit.vue'
import axios from 'axios'
// TODO: 列表渲染
//思路:声明响应式数据list->调用接口获取数据->后端数据赋值给list ->绑定到table组件
const list = ref([])
const getList = async () => {
//接口调用
const res=await axios.get('/list')//都是mock的假数据,后端没有完成的话,就可以这样
list.value=res.data
}
onMounted(() => {
getList()
})
// TODO: 删除功能
//思路:获取当前行的id->调用接口->更新数据->重新渲染
const onDelete = async (id) =>{
console.log(id);
await axios.delete(`/del/${id}`)
getList()
}
// TODO: 新增功能
// TODO: 编辑功能
</script>
<template>
<div class="app">
<el-table :data="list">
<el-table-column label="ID" prop="id"></el-table-column>
<el-table-column label="姓名" prop="name" width="150"></el-table-column>
<el-table-column label="籍贯" prop="place"></el-table-column>
<el-table-column label="操作" width="150">
<template #default="{row}">
<el-button type="primary" link>编辑</el-button>
<el-button type="danger" @click="onDelete(row.id)" link>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<Edit />
</template>
<style scoped>
.app {
width: 980px;
margin: 100px auto 0;
}
</style>
Edit.vue
<script setup>
// TODO: 编辑
import { ref } from 'vue'
// 弹框开关
const dialogVisible = ref(false)
</script>
<template>
<el-dialog v-model="dialogVisible" title="编辑" width="400px">
<el-form label-width="50px">
<el-form-item label="姓名">
<el-input placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="籍贯">
<el-input placeholder="请输入籍贯" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<style scoped>
.el-input {
width: 290px;
}
</style>
mock的假数据
import Mock from "mockjs"
// 内存模拟数据
const arr = []
for (let i = 0; i < 10; i++) {
arr.push({
id: Mock.mock("@id"),
name: Mock.mock("@cname"),
place: Mock.mock("@county(true)"),
})
}
export default [
{
url: "/list",
method: "get",
response: () => {
return arr
},
},
{
url: "/del/:id",
method: "delete",
response: (req) => {
const index = arr.findIndex((item) => item.id === req.query.id)
if (index > -1) {
arr.splice(index, 1)
return { success: true }
} else {
return { success: false }
}
},
},
{
url: "/edit/:id",
method: "patch",
response: ({ query, body }) => {
const item = arr.find((item) => item.id === query.id)
if (item) {
item.name = body.name
item.place = body.place
return { success: true }
} else {
return { success: false }
}
},
},
]
新增和编辑功能就不写了
Day 2 pinia和项目起步
1.1添加pinia到项目
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
//1.导入createPinia方法
import { createPinia } from 'pinia'
//2.执行方法得到实例
const pinia = createPinia()
//3.把pinia 实例加入到app应用中
createApp(App).use(pinia).mount('#app')
定义store
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
// 定义数据 state
const count = ref(0)
//定义修改数据的方法(action 同步加异步)
const increment = () => {
count.value++
}
return { count, increment }
})
使用
<script setup>
// 1.导入use 打头的方法
import {useCounterStore} from '@/stores/counter'
//2.执行方法得到store实例对象
const counterStore = useCounterStore()
console.log(counterStore)
</script>
<template>
<div>
</div>
<button @click='counterStore.increment'>{
{ counterStore.count }}</button>
</template>
<style scoped>
</style>
1.2getter 计算属性
counter.js
// stores/counter.js
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
// 定义数据 state
const count = ref(0)
//定义修改数据的方法(action 同步加异步)
const increment = () => {
count.value++
}
//getter定义计算属性
const doubleCount = computed(() => count.value * 2)
return {
count,
increment,
doubleCount
}
})
App.vue
<script setup>
// 1.导入use 打头的方法
import { useCounterStore } from '@/stores/counter'
//2.执行方法得到store实例对象
const counterStore = useCounterStore()
console.log(counterStore)
</script>
<template>
<div>
{
{ counterStore.doubleCount }}
</div>
<button @click='counterStore.increment'>{
{ counterStore.count }}</button>
</template>
<style scoped></style>
1.3action异步
App.vue
<script setup>
// 1.导入use 打头的方法
import { onMounted } from 'vue'
import { useCounterStore } from '@/stores/counter'
//2.执行方法得到store实例对象
const counterStore = useCounterStore()
console.log(counterStore)
onMounted(() => {
counterStore.getList()
})
</script>
<template>
<div>
{
{ counterStore.doubleCount }}
</div>
<button @click='counterStore.increment'>{
{ counterStore.count }}</button>
<ul>
<li v-for='item in counterStore.list' :key='item.id'>{
{ item.name }}</li>
</ul>
</template>
<style scoped></style>
counter.js
// stores/counter.js
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { computed } from 'vue'
import axios from 'axios'
export const useCounterStore = defineStore('counter', () => {
// 定义数据 state
const count = ref(0)
//定义修改数据的方法(action 同步加异步)
const increment = () => {
count.value++
}
//getter定义计算属性
const doubleCount = 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 {
count,
increment,
doubleCount,
list,
getList
}
})
1.4storeToRefs和调试
直接解构赋值(响应式丢失)
<script setup>
// 1.导入use 打头的方法
import { onMounted } from 'vue'
import { useCounterStore } from '@/stores/counter'
//2.执行方法得到store实例对象
const counterStore = useCounterStore()
console.log(counterStore)
//直接解构赋值(响应式丢失)
const{ doubleCount, increment, list ,count }=counterStore
// 触发action
onMounted(() => {
counterStore.getList()
})
</script>
<template>
<div>
{
{ doubleCount }}
</div>
<button @click='counterStore.increment'>-{
{ count }}</button>
<ul>
<li v-for='item in counterStore.list' :key='item.id'>{
{ item.name }}</li>
</ul>
</template>
<style scoped></style>
保持数据响应式
<script setup>
// 1.导入use 打头的方法
import { onMounted } from 'vue'
import { useCounterStore } from '@/stores/counter'
import {storeToRefs} from 'pinia'
//2.执行方法得到store实例对象
const counterStore = useCounterStore()
console.log(counterStore)
//直接解构赋值(响应式丢失)
// const{ doubleCount, increment, list ,count }=counterStore
//方法包裹(保持响应式)
const{ doubleCount, increment, list ,count }=storeToRefs(counterStore)
// 触发action
onMounted(() => {
counterStore.getList()
})
</script>
<template>
<div>
{
{ doubleCount }}
</div>
<button @click='counterStore.increment'>-{
{ count }}</button>
<ul>
<li v-for='item in counterStore.list' :key='item.id'>{
{ item.name }}</li>
</ul>
</template>
<style scoped></style>
方法直接从原来的counterStore中结构赋值
<script setup>
// 1.导入use 打头的方法
import { onMounted } from 'vue'
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
//2.执行方法得到store实例对象
const counterStore = useCounterStore()
console.log(counterStore)
//直接解构赋值(响应式丢失)
// const{ doubleCount, increment, list ,count }=counterStore
//方法包裹(保持响应式)
const { doubleCount, list, count } = storeToRefs(counterStore)
//方法直接从原来的counterStore中结构赋值
const{ increment } = counterStore
// 触发action
onMounted(() => {
counterStore.getList()
})
</script>
<template>
<div>
{
{ doubleCount }}
</div>
<button @click='increment'>-{
{ count }}</button>
<ul>
<li v-for='item in counterStore.list' :key='item.id'>{
{ item.name }}</li>
</ul>
</template>
<style scoped></style>