生命周期钩子
App.vue
<template>
<div>
<button @click="increment">{{ counter }}</button>
</div>
</template>
<script>
import { onMounted, onUpdated, onUnmounted, ref } from 'vue'
export default {
setup() {
const counter = ref(0)
const increment = () => counter.value++
// 【不推荐使用beforeCreate、created了,如果需要做这2个函数做的操作,可以在setup里面做,setup在这2个函数之前执行。】
// 【同一个生命周期可以使用多次,每次都会执行,这样就可以将某一个抽离到hooks中。】
onMounted(() => {
console.log('App Mounted1')
})
onMounted(() => {
console.log('App Mounted2')
})
onUpdated(() => {
console.log('App onUpdated')
})
onUnmounted(() => {
console.log('App onUnmounted')
})
return {
counter,
increment,
}
},
}
</script>
<style scoped></style>
写的App.vue
<template>
<div>
<h3 ref="numRef">num的值是: {{ num }}</h3>
<button @click="addOne">+1</button>
</div>
</template>
<script>
import { ref, onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
const num = ref(100)
const numRef = ref(null)
const addOne = () => num.value++
onBeforeUpdate(() => {
console.log('onBeforeUpdate') // onBeforeUpdate
// <h3>num的值是: 101</h3> "object"
console.log(numRef.value, typeof numRef.value)
// 要通过 value.innerHTML 这种方式才能拿到界面变化前后的值
console.log(numRef.value.innerHTML) // num的值是: 100
})
onUpdated(() => {
// onUpdated <h3>num的值是: 101</h3>
console.log('onUpdated', numRef.value)
console.log(numRef.value.innerHTML) // num的值是: 101
})
return {
num,
numRef,
addOne,
}
},
}
</script>
Provide函数
Inject函数
数据的响应式
修改响应式Property
App.vue
<template>
<div>
<home />
<h2>App Counter: {{ counter }}</h2>
<button @click="increment">App中的+1</button>
</div>
</template>
<script>
import { provide, ref, readonly } from 'vue'
import Home from './Home.vue'
export default {
components: {
Home,
},
setup() {
const name = ref('haha')
let counter = ref(100)
provide('name', readonly(name))
provide('counter', readonly(counter))
const increment = () => counter.value++
return {
increment,
counter,
}
},
}
</script>
<style scoped></style>
Home.vue
<template>
<div>
<h2>{{ name }}</h2>
<h2>{{ counter }}</h2>
<button @click="homeIncrement">home+1</button>
</div>
</template>
<script>
import { inject } from 'vue'
export default {
setup() {
// 参数1:key,参数2:默认值,可以不写
const name = inject('name')
const counter = inject('counter')
const homeIncrement = () => counter.value++
return {
name,
counter,
homeIncrement,
}
},
}
</script>
<style scoped></style>
useCounter
useCounter.js
import { ref, computed } from 'vue'
export default function () {
const counter = ref(0)
const doubleCounter = computed(() => counter.value * 2)
const increment = () => counter.value++
const decrement = () => counter.value--
return {
counter,
doubleCounter,
increment,
decrement,
}
}
useTitle
useTitle.js
import { ref, watch } from 'vue'
// 场景:title要根据某个变量修改,根据返回值修改title
export default function (title = '默认的title') {
const titleRef = ref(title)
watch(
titleRef,
newValue => {
document.title = newValue
},
{
immediate: true,
}
)
return titleRef
}
import { ref } from 'vue'
export default function () {
const scrollX = ref(0)
const scrollY = ref(0)
document.addEventListener('scroll', () => {
scrollX.value = window.scrollX
scrollY.value = window.scrollY
})
return {
scrollX,
scrollY,
}
}
useMousePosition
useMousePosition.js
import { ref } from 'vue'
export default function () {
const mouseX = ref(0)
const mouseY = ref(0)
window.addEventListener('mousemove', event => {
mouseX.value = event.pageX
mouseY.value = event.pageY
})
return {
mouseX,
mouseY,
}
}
useLocalStorage
useLocalStorage.js
import { ref, watch } from 'vue'
export default function (key, value) {
const data = ref(value)
if (value) {
window.localStorage.setItem(key, JSON.stringify(value))
} else {
data.value = JSON.parse(window.localStorage.getItem(key))
}
watch(data, newValue => {
window.localStorage.setItem(key, JSON.stringify(newValue))
})
return data
}
// 一个参数: 取值
// const data = useLocalStorage("name");
// // 二个参数: 保存值
// const data = useLocalStorage("name", "haha");
// data.value = "kobe";
index.js
import useCounter from './useCounter'
import useTitle from './useTitle'
import useScrollPosition from './useScrollPosition'
import useMousePosition from './useMousePosition'
import useLocalStorage from './useLocalStorage'
export {
useCounter,
useTitle,
useScrollPosition,
useMousePosition,
useLocalStorage,
}
setup顶层编写方式
App.vue
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<button @click="increment">+1</button>
<hello-world message="呵呵呵" @increment="getCounter"></hello-world>
</div>
</template>
<script setup>
import { ref } from 'vue'
import HelloWorld from './HelloWorld.vue'
const counter = ref(0)
const increment = () => counter.value++
const getCounter = payload => {
console.log(payload)
}
</script>
<style scoped></style>
HelloWorld.vue
<template>
<div>
<h2>Hello World</h2>
<h2>{{ message }}</h2>
<button @click="emitEvent">发射事件</button>
</div>
</template>
<script setup>
import { defineProps, defineEmit } from 'vue'
const props = defineProps({
message: {
type: String,
default: '哈哈哈',
},
})
const emit = defineEmit(['increment', 'decrement'])
const emitEvent = () => {
emit('increment', '100000')
}
</script>
<style scoped></style>
认识h函数
h()函数 如何使用呢?
h函数的基本使用
h函数计数器案例
函数组件和插槽的使用
01_render的基本使用.vue
<script>
import { h } from 'vue'
export default {
render() {
return h('h2', { class: 'title' }, 'Hello Render')
},
}
</script>
<style scoped></style>
02_render函数实现计数器.vue
<script>
import { h } from 'vue'
export default {
data() {
return {
counter: 0,
}
},
render() {
return h('div', { class: 'app' }, [
h('h2', null, `当前计数: ${this.counter}`),
h(
'button',
{
onClick: () => this.counter++,
},
'+1'
),
h(
'button',
{
onClick: () => this.counter--,
},
'-1'
),
])
},
}
</script>
<style scoped></style>
03_setup函数实现计数器.vue
<script>
import { ref, h } from 'vue'
export default {
setup() {
const counter = ref(0)
return () => {
return h('div', { class: 'app' }, [
h('h2', null, `当前计数: ${counter.value}`),
h(
'button',
{
onClick: () => counter.value++,
},
'+1'
),
h(
'button',
{
onClick: () => counter.value--,
},
'-1'
),
])
}
},
}
</script>
<style scoped></style>
App.vue
<script>
import { h } from 'vue'
import HelloWorld from './HelloWorld.vue'
export default {
render() {
return h('div', null, [
h(HelloWorld, null, {
default: props =>
h('span', null, `app传入到HelloWorld中的内容: ${props.name}`),
}),
])
},
}
</script>
<style scoped></style>
HelloWorld.vue
<script>
import { h } from 'vue'
export default {
render() {
return h('div', null, [
h('h2', null, 'Hello World'),
this.$slots.default
? this.$slots.default({ name: 'coderwhy' })
: h('span', null, '我是HelloWorld的插槽默认值'),
])
},
}
</script>
<style lang="scss" scoped></style>
jsx的babel配置
jsx计数器案例
jsx组件的使用
App.vue
<script>
import HelloWorld from './HelloWorld.vue'
export default {
data() {
return {
counter: 0,
}
},
render() {
const increment = () => this.counter++
const decrement = () => this.counter--
return (
<div>
<h2>当前计数: {this.counter}</h2>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
<HelloWorld></HelloWorld>
</div>
)
},
}
</script>
<style lang="scss" scoped></style>
HelloWorld.vue
<script>
export default {
render() {
return (
<div>
<h2>HelloWorld</h2>
{this.$slots.default ? this.$slots.default() : <span>哈哈哈</span>}
</div>
)
},
}
</script>
<style scoped></style>