Vue高级语法
1.生命周期钩子
-
setup可以代替之前的data,methods,computed,wacth等等这些选项,也可以替代生命周期钩子。
-
那咋使用在setup函数中?
- 很简单,直接导入on + X函数注册生命周期钩子
<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++
onMounted(() => {
console.log("App Mounted");
})
onUpdated(() => {
console.log("App onUpdated");
})
onUnmounted(() => {
console.log("App onUnmounted");
})
return {
counter,
increment
}
}
}
</script>
<style scoped>
</style>
⚠️ 在Composition API中使用setup代替beforeCreate和created因为setup其实执行的更早一些
2.provide与Inject在setup中使用
-
我们可以通过provide来提供数据:
-
可以通过provide方法来定义每个Property
-
provide可以传入两个参数:
- Name: 提供的属性名称
- Value: 提供的属性值
-
在后代组件中可以通过inject来注入需要的属性和对应的值:
-
inject可以传入两个参数
- inject的property的name
- 给一个默认值(选写)
-
-
App.vue
<template>
<div>
<Home />
<button @click="increment"></button>
</div>
</template>
<script>
import Home rom "./Home.vue"
improt {provide,ref,readonly} from "vue"
export default {
components: {
Home
},
setup() {
//尽量使用ref,因为这两个玩意就没什么关联性
const name = ref("Tim");
let counter = ref(100);
//为什么要使用readyonly呢,假设我在子组件使用点击事件把counter或者name进行了修改,这样也会把父组件的东西修改了,我们要遵循一个原则就是单项数据流,使用使用readonly传过去的只可以读取不能进行修改
provide("name",readonly(name))
provide("counter",counter)
const increment = () => {
counter++
}
return {
increment,
}
}
}
</script>
- Home.vue
<template>
<div>
<h2>{{name}}</h2>
<h2>{{counter}}</h2>
</div>
</template>
<script>
improt {inject} from "vue"
export default {
setup() {
const name = inject("name")
const counter = inject("counter")
return {
name,counter
}
}
}
</script>
3.hooks
- 如果使用option API会使用代码不易阅读
- 换成setup就会简介很多,但是也会随着代码量越写越多,所以一般会把功能进行抽离放在js文件中如何再进行使用,这就是hooks的概念。
案例1:
//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
}
}
<template>
<div>
<!-- 计数器案例 -->
<h2>当前计数: {{counter}}</h2>
<h2>计数*2: {{doubleCounter}}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script>
import useCounter from "./hooks/useCounter"
setup() {
const {counter,doubleCounter,increment,decrement} = useCounter()
return {
counter,doubleCounter,increment,decrement
}
}
</script>
案例2:
//useTittle.js
import {ref,watch} from "vue"
export default function(title="我是默认值title") {
const titleRef = ref(title)
watch(titleRef,(newValue)=> {
document.title = newValue
},{
immediate:true
})
return titleRef
}
<template>
<div>
</div>
</template>
<script>
import useTittle from "./hooks/useTittle"
setup() {
const titleRef = useTittle("tim")
setTimeout(() => {
titleRef.value = "yang"
},2000)
return {
}
}
</script>
案例3:
<p class="content"></p>
<div class="scroll">
<div class="scroll-x">scrollX: {{scrollX}}</div>
<div class="scroll-y">scrollY: {{scrollY}}</div>
</div>
<script>
import useScrollPosition from "./hooks/useScrollPosition.js"
export defualt {
setup() {
const {scrollX,scrollY} = useScrollPosition()
return {
scrollX,
scrollY
}
}
}
</script>
//useScrollPosition.js
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
}
}
案例4:
//useMousePosition.js
import {ref} from "vue"
export default function() {
const mouseX = ref(0)
const mouseY = ref(0)
window.addEventListener("mouseover",(event)=> {
mouseX.value = event.pageX;
mouseY.value = event.pageY;
})
return {
mouseX,
mouseY
}
}
<p class="content"></p>
<div class="mouse">
<div class="mouse-x">mouseX: {{mouseX}}</div>
<div class="mouse-y">mouseY: {{mouseY}}</div>
</div>
<script>
import useMousePosition from "./hooks/useMousePosition.js"
export defualt {
setup() {
const {mouseX,mouseY} = useMousePosition()
return {
mouseX,
mouseY
}
}
}
</script>
案例5:
//useLocalStorage.js
import {ref,watch} from "vue"
export default function(key,value) {
const data = ref(value)
if(value) {
window.localStorage.setItem(key,JSON.strigify(value))
}else {
data.value=JSON.parse(window.localStorage.getItem(key))
}
watch(data,(newValue)=> {
window.localStorage.setItem(key,JSON.strigify(value))
})
return data
}
<template>
<h2>
{{data}}
</h2>
<button @click="changeData">
修改data
</button>
</template>
<script>
import useLocalStorage from "./hooks/useLocalStorage.js"
export default {
setup() {
//localStroage
const data = useLocalStorage("info",{name:"Tim",age:21})
}
const changeData = () => data.value = "修改值"
return {
data,
changeData
}
}
</script>
4.h函数
-
Vue推荐绝大多数情况下使用模版来创建你的HTML,然后一些特殊的场景,你真的需要JavaScript完全编程能力就可以使用渲染函数
- Vue在生成真实的DOM之前,会把节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM(VDom)
- 事实上,template中的HTML最终也会使用渲染函数生成对应的VNode
- 你可以充分利用javascript编程能力编写createVNode函数,生成对应VNode
-
那么就可以使用h函数
- h()函数是用于创建VNode的一个函数
-
如何进行使用呢?
-
来看看实际操作
-
<script>
import {h} from "vue"
export default {
setup() {
return () => h("h2",{class:"title"},"hello render")
}
}
</script>
小案例:
<script>
import {h,ref} from "vue"
export default {
setup() {
const counter = ref(0)
return () => {
return h("h2",{class:"title"},[
h("h2",null,`当前计数:${counter.value}`),
h("button",{
onClick:() => counter.value++
},"+1")
h("button",{
onClick:() => counter.value--
},"-1")
])
}
}
}
</script>
如果要把使用第一个参数是组件还有插槽怎么使用呢?
上代码看看👀
- 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: "tim"}): h("span", null, "我是HelloWorld的插槽默认值")
])
}
}
</script>
<style lang="scss" scoped>
</style>
5.JSX
-
如果要在项目中使用jsx,就需要添加jsx的对应支持
- jsx通常是用babel进行转换
- 在Vue中,只需要在Babel配置对应的插件就可以了
-
安装jsx插件
npm install @vue/babel-plugin-jsx -D
- 在babel.config.js配置文件中配置插件
//babel.config.js
module.exports = {
presets: [
"@/vue/cli-plugin-babel/preset"
],
plugins: [
"@vue/babel-plugin-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>
{{default:props => <button>我是按钮</button>}}
</HelloWorld>
<div>
)
}
}
</script>
jsx组件和插槽使用
- HelloWorld.vue
<script>
export default {
render() {
return(
<div>
<h2>helloworld</h2>
{this.$slots.default ? this.$slots.default() : <span>默认值</span>}
</div>
)
}
}
</script>