1.必包的妙用
// 先看一个从0加到3的例子
const count = (a, b) => a + b // 最简单的加法
const foo1 = count(0, 1)
const foo2 = count(foo1, 2)
const foo3 = count(foo2, 3)
console.log(foo3) // 输出6
上边的代码比较不好的地方就是依赖非常多的标识符,0加到3需要标识符foo1, foo2, foo3
。太多的标识符意味这你的选择就越多(想象一下你需要从0加到100,标识符能写到你吐血),你需要确保下一个函数调用所依赖的标识符是正确的,这将导致出现错误的概率大大增加。
// 使用必包简化之后
const useCount = () => {
let a = 0
return (b) => {
a = a + b
return a
}
}
// 我们都知道箭头函数只有一个返回值时是可以不需要函数体和return的
const useCount = () => {
let a = 0
return (b) => (a = a + b)
}
// 于是我们使用useCount来做0加到3就变成了下边这样
const count = useCount()
count(1) // 此时必包所引用的标识符a = 0 + 1
count(2) // 同理, a = 1 + 2, 你会发现上次count函数调用后,a被记录下来了
const foo = count(3) // 同理, a = 3 + 3
console.log(foo) // 输出6
// 啥啥?? a 默认只能从0开始????
const useCount = () => {
let a = 0 // a 默认只能从0开始????
return (b) => (a = a + b)
}
// 这里如果你对必包有一个较深的理解的话,你会将useCount优化为下边这样
// 必包是一个函数,就是我们上边返回的那个函数(b) => (a = a + b)
// 必包有一个特征就是引用了父级函数的标识符,不论调用多少次都是引用的同一个标识符即a
// 这里你就会想到父级函数的形参也是父级函数定义的标识符呀
// 于是你会写成下边这样
const useCount = (a) => {
return (b) => (a = a + b)
}
const count = useCount(1) // 此时a从1开始,这里你第一实参是啥,a就是啥
count(2)
const foo = count(3)
console.log(foo) // 输出6
// 都说了,箭头函数只有一个返回值时是可以不需要函数体和return的
const useCount = (a) => (b) => (a = a + b)
// 另外大家都知道,箭头函数只有一个形参(无默认值)时可以省略参数的小括号
const useCount = a => b => (a = a + b)
// 于是最终版就是
const useCount = a => b => (a = a + b)
const count = useCount(1)
count(2)
const foo = count(3)
console.log(foo) // 输出6
const foo2 = count(4) // 随时返回值,不会出现断层,即使前边有被标识符foo接收了
console.log(foo2) // 输出10
const foo3 = count(5) // 此时a = 10 + 5
// 这里的 count1 不会与count冲突,因为是不同的a
// 每次调用useCount都会生成一个新的状态,即新的必包与其新的父级标识符引用(a)
const count1 = useCount(100)
count1(200)
const bar = count1(300)
console.log(bar) // 输出600
那么回顾这个必包
有什么用呢???其实你会发现上边的count
与count1
可以在保存一个状态的同时做到不冲突。这又怎么样呢???(小兄弟你前摇有点长哦!!)
那么我们快快进入到与vue3-api
结合吧!!
2. vue3 函数式实践
先来个简单点的例子吧,太难的话可能大家接受不了。(有点嚣张哦)
// 还是上边的例子
// @/use/count.js
const useCount = a => b => (a = a + b)
export default useCount
// @/components/foo.vue
<template>
<section>
foo组件
<!-- val将会是6 -->
<div>val - {{ val }}</div>
</section>
</template>
<script>
import useCount from "@/use/count.js"
export default {
setup() {
// 从0加到3的例子
const count = useCount(0)
count(1)
count(2)
return {
val: count(3) // 最后一定要用一个值来接收,因为count是函数不是值
}
}
}
</script>
看到这里你会说,"丢,完哇咩?这有啥用呀??"
// 于是我将它改为下边这样
// @/use/count.js
const useCount = a => b => (a = a + b)
export const count = useCount(0)
// @/components/foo.vue
<template>
<section>
foo组件
<div>val - {{ val }}</div>
</section>
</template>
<script>
import { count } from "@/use/count.js"
export default {
setup() {
count(1)
count(2)
return {
val: count(3)
}
}
}
</script>
// @/components/bar.vue
<template>
<section>
bar组件
<div>val - {{ val }}</div>
</section>
</template>
<script>
import { count } from "@/use/count.js"
export default {
setup() {
count(1)
count(2)
return {
val: count(3)
}
}
}
</script>
// App.vue
// foo组件与bar组件为兄弟组件
<template>
<foo />
<bar />
</template>
<script>
import foo from "@/components/foo.vue"
import bar from "@/components/bar.vue"
export default {
components: {
foo,
bar
}
}
</script>
天,他们能叠加??
对的!
那这能做啥东东呢??
其实很简单,就是状态共享!
于是
基于必包
与vue3提供的api
可以做状态共享
,而不需要依赖vuex
// @/use/state.js
import { ref } from "vue"
const useState = (initState) => {
const state = ref(initState)
return (newState = state.value) => {
state.value = newState
return state
}
}
// 这是一个共享的状态
export const useName = useState("name")
// @/components/foo.vue
<template>
foo组件
<section>共享name - {{name}}</section>
<button @click="useName('foo')"> 改name为foo </button>
</template>
<script>
import { useName } from "@/use/state.js"
export default {
setup() {
const name = useName()
return {
name,
useName
}
}
}
</script>
// @/components/bar.vue
<template>
bar组件
<section>共享name - {{name}}</section>
<button @click="useName('bar')"> 改name为bar </button>
</template>
<script>
import { useName } from "@/use/state.js"
export default {
setup() {
const name = useName()
return {
name,
useName
}
}
}
</script>
// App.vue
// foo组件与bar组件为兄弟组件
<template>
<foo />
<bar />
</template>
<script>
import foo from "@/components/foo.vue"
import bar from "@/components/bar.vue"
export default {
components: {
foo,
bar
}
}
</script>
<style>
// 加了点样式,这不是重点,不需要纠结
#app > * {
margin: 20px;
padding: 20px;
background-color: antiquewhite;
text-align: center;
}
</style>
这里你会发现,你点击兄弟组件的任何一个button都可以响应到彼此的name上。于是我们就可以基于此做状态的共享。
用上setup
语法糖后会更简洁
// @/components/foo.vue
<template>
foo组件
<section>共享name - {{name}}</section>
<button @click="useName('foo')"> 改name为foo </button>
</template>
<script setup>
import { useName } from "@/use/state.js"
const name = useName()
</script>
// @/components/bar.vue
<template>
bar组件
<section>共享name - {{name}}</section>
<button @click="useName('bar')"> 改name为bar </button>
</template>
<script setup>
import { useName } from "@/use/state.js"
const name = useName()
</script>
// App.vue
// foo组件与bar组件为兄弟组件
<template>
<foo />
<bar />
</template>
<script setup>
import foo from "@/components/foo.vue"
import bar from "@/components/bar.vue"
</script>
<style>
// 加了点样式,这不是重点,不需要纠结
#app > * {
margin: 20px;
padding: 20px;
background-color: antiquewhite;
text-align: center;
}
</style>
这里你会发现你的useState
和useName
根本不需要在同一个模块下。于是你可以抽出自己的共享状态域,就是store目录
// @/use/state.js
import { ref } from "vue"
// 这里重命名为useBaseState,因为这是最基础的,后边有必要的话,我再写更难一点的函数
export const useBaseState = initState => {
const state = ref(initState)
return (newState = state.value) => {
state.value = newState
return state
}
}
// @/store/user.js
import { useBaseState } from "@/use/state"
export useUserName = useBaseState("user_name")
export useUserAge = useBaseState(18)
export useUserGender = useBaseState("man")
// 这里如果想要更简洁,可以对象来包裹
import { useBaseState } from "@/use/state"
export const sharedUser = {
name: useBaseState("user_name"),
age: useBaseState(18),
gender: useBaseState("man")
}
// @/components/user.vue
<template>
<section>
user
<div>{{ name }}</div>
<div>{{ age }}</div>
<div>{{ gender }}</div>
</section>
</template>
<script setup>
import { sharedUser } from "../store/user"
const name = sharedUser.name("张三")
const age = sharedUser.age(30)
const gender = sharedUser.gender("男")
</script>
// @/components/user-form.vue
<template>
<main class="user-form">
<section>name: <input v-model="name" /></section>
<section>age: <input v-model="age" /></section>
<section>gender: <input v-model="gender" /></section>
</main>
</template>
<script setup>
import { sharedUser } from "../store/user"
const name = sharedUser.name()
const age = sharedUser.age()
const gender = sharedUser.gender()
</script>
<style scoped>
.user-form > * {
margin-top: 10px;
}
</style>
// App.vue
<template>
<user />
<user-form />
</template>
<script setup>
import user from "./components/user.vue"
import userForm from "./components/user-form.vue"
</script>
<style>
#app > * {
margin: 20px;
padding: 20px;
background-color: antiquewhite;
text-align: center;
}
</style>
效果大概就是下边这样,非常简单就可以做到状态共享。
关于vue3
的函数入门实践大概就是这样,对于基础较好的同学会比较简单,而基础不好的同学则不然。假如上边的例子你觉得稍微难了点,可以去巩固一下vue3基础api使用
以及必包
的相关知识!!
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!