最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue3函数式实践 - 更简洁高效的写法实践(保姆级)

    正文概述 掘金(骑自行车)   2021-03-10   682

    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
    

    ​ 那么回顾这个必包有什么用呢???其实你会发现上边的countcount1可以在保存一个状态的同时做到不冲突。这又怎么样呢???(小兄弟你前摇有点长哦!!)

    那么我们快快进入到与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>
    

    vue3函数式实践 - 更简洁高效的写法实践(保姆级)

    这里你会发现,你点击兄弟组件的任何一个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>
    

    这里你会发现你的useStateuseName根本不需要在同一个模块下。于是你可以抽出自己的共享状态域,就是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的函数入门实践大概就是这样,对于基础较好的同学会比较简单,而基础不好的同学则不然。假如上边的例子你觉得稍微难了点,可以去巩固一下vue3基础api使用以及必包的相关知识!!


    起源地下载网 » vue3函数式实践 - 更简洁高效的写法实践(保姆级)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元