最近,我的朋友因为不熟悉 Vue.js 而未能通过面试。
她平时工作中大部分时间都在使用React,所以也懒得去了解其他前端框架。
世界上所有的前端框架我们都应该熟悉吗?
不,这是极其不合理的。
但为了生存,朋友还是要学习Vue的框架。
让我们看看如何使用 Vue 来实现 React 的一些功能。
控制元素或组件的显示和隐藏是我们最常见的事情之一,在React中,我们经常这样编码。
JavaScript 中的三元表达式和“&”也可以实现同样的目标。
import React, { useState } from "react"export default function Vif (){ const [ isShow, setIsShow ] = useState(true) const onToggleShow = () => { setIsShow(!isShow) } return ( <div className="v-if"> <button onClick={ onToggleShow }>Toggle</button> {/* Of course you can also use ternary expressions */} {/* isShow ? <div>fatfish has shown</div> : null */} { isShow && <div>fatfish has shown</div> } </div> )}
那么在Vue中如何实现同样的功能呢?
是的,我们可以使用 v-if 指令来控制元素的显示和隐藏,这很简单,不是吗?
<template> <div class="v-if"> <button @click="onToggleShow">Toggle</button> <div v-if="isShow">fatfish has shown</div> </div></template><script>export default { name: 'vif', data () { return { isShow: true } }, methods: { onToggleShow () { this.isShow = !this.isShow } }}</script>
v-if 导致元素或组件被重复删除和创建,如果我们只想“显示”或“隐藏”它怎么办?
也许我们可以借助 CSS 中的 display 属性来做到这一点。
import React, { useState } from "react"export default function VShow (){ const [ isShow, setIsShow ] = useState(true) const onToggleShow = () => { setIsShow(!isShow) } return ( <div className="v-show"> <button onClick={ onToggleShow }>Toggle</button> { <div style={{ display: isShow ? '' : 'none' }}>fatfish has shown</div> } </div> )}
你可能已经猜到了,我们可以使用 v-show 来实现与它相同的功能。看起来 Vue 更简洁,你不觉得吗?
<template><div class="v-show"> <button @click="onToggleShow">Toggle</button> <div v-show="isShow">fatfish has shown</div> </div></template><script>export default { name: 'vshow', data () { return { isShow: true } }, methods: { onToggleShow () { this.isShow = !this.isShow } }}</script>
在React中,我们可以使用数组的map方法来创建列表,这非常简单。
看一下这段代码,它创建了三个不同职业的列表。
import React, { useState } from "react"export default function VFor (){ const [ list, setList ] = useState([ { id: 1, name: 'Front end', }, { id: 2, name: 'Android', }, { id: 3, name: 'IOS', }, ]) return ( <div className="v-for"> { list.map((item) => { return <div key={ item.id } className="v-for-item">{ item.name }</div> }) } </div> )}
你喜欢 Vue 中的 v-for 指令吗?
<template> <div class="v-for"> <div class="v-for-item" v-for="item in list" :key="item.id"> {{ item.name }} </div> </div></template><script>export default { name: "vfor", data() { return { list: [ { id: 1, name: "Front end", }, { id: 3, name: "Android", }, { id: 4, name: "IOS", }, ], }; },};</script>
如果我们想计算两个数的和,有什么好的方法吗?
我的意思是,当 num1 和 num2 发生变化时,它们的总和会自动变化,我们不需要手动处理。
import React, { useMemo, useState } from "react"export default function Computed (){ const [ num1, setNum1 ] = useState(10) const [ num2, setNum2 ] = useState(10) const num3 = useMemo((a, b) => { return num1 + num2 }, [ num1, num2 ]) const onAdd = () => { setNum1(num1 + 10) } return ( <div className="computed"> <button onClick={ onAdd }>+10</button> <div>result:{ num3 }</div> </div> )}
哇,太棒了,useMemo 帮我们解决了一个问题。
那么,Vue中有没有更好的实现呢?它实际上提供了一种称为“计算”的机制,该机制更智能且更易于使用。
<template> <div class="computed"> <button @click="onAdd">+10</button> <div>result:{{ num3 }}</div> </div></template><script>export default { name: 'computed', data () { return { num1: 10, num2: 10, } }, computed: { num3 () { return this.num1 + this.num2 } }, methods: { onAdd () { this.num1 += 10 } }}</script>
当我们需要监听数据变化然后执行回调函数时,可以在React中使用useEffect来完成。
让我们尝试模拟一个场景:
我们点击男孩或女孩按钮,选中时发送请求,最后显示请求结果(我们通过setTimeout模拟异步请求过程)。
export default function Watch() { const [fetching, setFetching] = useState(false) const [selects, setSelects] = useState([ 'boy', 'girl' ]) const [selectValue, setSelectValue] = useState('') const result = useMemo(() => { return fetching ? 'requesting...' : `the result of the request: ${selectValue || '~'}` }, [ fetching ]) const onSelect = (value) => { setSelectValue(value) } const fetch = () => { if (!fetching) { setFetching(true) setTimeout(() => { setFetching(false) }, 1000) } } // Pay attention here useEffect(() => { fetch() }, [ selectValue ]) return ( <div className="watch"> <div className="selects"> { selects.map((item, i) => { return <button key={ i } onClick={ () => onSelect(item) }>{ item }</button> }) } </div> <div className="result"> { result } </div> </div> )}
别担心,我们可以在 Vue 中做同样的事情,你知道它的秘密是什么吗?
是的,答案是watch。
<template> <div class="watch"> <div class="selects"> <button v-for="(item, i) in selects" :key="i" @click="onSelect(item)" > {{ item }} </button> </div> <div class="result"> {{ result }} </div> </div></template><script>export default { name: 'watch', data () { return { fetching: false, selects: [ 'boy', 'girl' ], selectValue: '' } }, computed: { result () { return this.fetching ? 'requesting...' : `the result of the request: ${this.selectValue || '~'}` } }, // Pay attention here watch: { selectValue () { this.fetch() } }, methods: { onSelect (value) { this.selectValue = value }, fetch () { if (!this.fetching) { this.fetching = true setTimeout(() => { this.fetching = false }, 1000) } } }}</script><style>button{ margin: 10px; padding: 10px;}</style>
有时我们需要动态地向元素添加样式,Vue 和 React 都为我们提供了一种便捷的使用方式。
从用途上来说,它们基本上是相似的。
相同点:
CSS 属性名称可以是驼峰命名法或短横线命名法(记住将它们用引号引起来)
差异:
import React from "react"export default function Style (){ const style = { width: '100%', height: '500px', } const style2 = { backgroundImage: 'linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%)', borderRadius: '10px', } return ( <div className="style" style={ { ...style, ...style2 } } ></div> )}
<template> <div class="style" :style="[ style, style2 ]"></div></template><script>export default { name: 'style', data () { return { style: { width: '100%', height: '500px', }, style2: { backgroundImage: 'linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%)', borderRadius: '10px', } } }}</script>
我们应该如何动态地为元素添加类?
在Vue中,我更喜欢使用数组语法(当然也有对象方式),在React中也可以使用一些第三方包比如classnames来起到更方便的方式来添加类的效果。
import React, { useMemo, useState } from "react"import './class.css'export default function Class (){ const [ isActive, setIsActive ] = useState(false) const buttonText = useMemo(() => { return isActive ? 'Selected' : 'UnSelected' }, [ isActive ]) const buttonClass = useMemo(() => { return [ 'button', isActive ? 'active' : '' ].join(' ') }, [ isActive ]) const onClickActive = () => { setIsActive(!isActive) } return ( <div className={ buttonClass } onClick={onClickActive}>{ buttonText }</div> )}
<template> <button :class="buttonClasses" @click="onClickActive">{{ buttonText }}</button></template><script>export default { name: 'class', data () { return { isActive: false, } }, computed: { buttonText () { return this.isActive ? 'Selected' : 'UnSelected' }, buttonClasses () { return [ 'button', this.isActive ? 'active' : '' ] } }, methods: { onClickActive () { this.isActive = !this.isActive } }}</script><style scoped>.button{ display: block; width: 100px; height: 30px; line-height: 30px; border-radius: 6px; margin: 0 auto; padding: 0; border: none; text-align: center; background-color: #efefef;}.active{ background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%); color: #fff}</style>
Vue 和 React 对于全局状态的管理都有自己很好的解决方案,比如 Vue 中的 Vuex、Redux 中的 React 和 Mobx,但是,当然,这些小项目的引入对于小用途来说有点太大了,就没有其他解决方案?
React 可以使用 Context
假设我们有一个用于用户信息的全局变量“userInfo”,需要在每个组件中轻松访问它,如何在Vue和React中实现它?
为了在 React 中实现这一点,您可以借助 Context 将全局状态共享给任何子节点。
上下文/index.js
import { createContext } from "react";export const UserInfoContext = createContext({ userInfo: { name: '' }})
import { UserInfoContext } from './context/index'function App() { return ( <BrowserRouter> // Pay attention here <UserInfoContext.Provider value={{ userInfo: { name: 'fatfish' } }} > <div className="title">I am React App</div> <Routes> <Route path="/v-if" element={<Vif />} /> <Route path="/v-show" element={<VShow />} /> <Route path="/v-for" element={<VFor />} /> <Route path="/computed" element={<Computed />} /> <Route path="/watch" element={<Watch />} /> <Route path="/style" element={<Style />} /> <Route path="/class" element={<Class />} /> <Route path="/slot" element={<Slot />} /> <Route path="/nameSlot" element={<NameSlot />} /> <Route path="/scopeSlot" element={<ScopeSlot />} /> <Route path="/provide" element={<Provide />} /> </Routes> </UserInfoContext.Provider> </BrowserRouter> );}
import React, { useContext } from "react"import { UserInfoContext } from '../context/index'export default function Provide() { // We can use the defined "UserInfoContext" through the userContext const { userInfo } = useContext(UserInfoContext) return ( <div class="provide-inject">{ userInfo.name }</div> )}
在Vue中,我们可以使用“provide/inject”将顶级状态传递给任何子节点,假设我们在app.vue中声明一个“userInfo”数据。
<template> <div id="app"> <div class="title">I am Vue App</div> <router-view/> </div></template><script>export default { name: 'app', // Pay attention here provide () { return { userInfo: { name: 'fatfish' } } }}</script>
<template> <div class="provide-inject">{{ userInfo.name }}</div></template><script>export default { name: 'provideInject', // Use data inject: [ 'userInfo' ]}</script>
假设我们要实现一个简单的对话组件,基本功能是标题可以作为字符串传递,内容部分可以完全自定义,我们应该如何实现呢?
虽然React中没有槽的概念,但是可以通过props.children获取组件内部的子元素,通过这个可以实现默认的槽。
import React, { useState, useEffect } from "react"import './dialog.css'export default function Dialog(props) { // Forgive me for implementing this in a silly way like visible -1 first, but that's not the point const { children, title = '', visible = -1 } = props const [visibleInner, setVisibleInner] = useState(false) const onHide = () => { setVisibleInner(false) } useEffect(() => { setVisibleInner(visible > 0) }, [ visible ]) return ( <div className="dialog" style={ { display: visibleInner ? 'block' : 'none' }}> <div className="dialog-mask" notallow={ onHide }></div> <div className="dialog-body"> { title ? <div className="dialog-title">{ title }</div> : null } <div className="dialog-main"> {/* Note here that the default slot function is implemented via children */} {children} </div> <div className="dialog-footer"> <div className="button-cancel" notallow={ onHide }>Cancel</div> <div className="button-confirm" notallow={ onHide }>Confirm</div> </div > </div > </div > )}
import React, { useState, useEffect } from "react"import Dialog from './components/dialog'export default function Slot() { const [visible, setVisible] = useState(-1) const onToggleVisible = () => { setVisible(Math.random()) } return ( <div className="slot"> <button onClick={ onToggleVisible }>Toggle</button> <Dialog visible={visible} title="default slot" > {/* Note that here, it will be read and replaced by the children of the Dialog component */} <div className="slot-body">fatfish</div> </Dialog> </div> )}
同样的功能在Vue中应该如何实现呢?
<template> <div class="dialog" v-show="visible"> <div class="dialog-mask" @click="onHide"></div> <div class="dialog-body"> <div class="dialog-title" v-if="title">{{ title }}</div> <div class="dialog-main"> <!-- Note: A default slot has been placed here --> <slot></slot> </div> <div class="dialog-footer"> <div class="button-cancel" @click="onHide">Cancel</div> <div class="button-confirm" @click="onHide">Confirm</div> </div> </div> </div></template><script>export default { name: "dialog", props: { title: { type: String, default: "", }, visible: { type: Boolean, default: false, }, }, methods: { onHide () { this.$emit('update:visible', false) } }};</script>
<template> <div class="slot"> <button @click="onToggleVisible">切换dialog</button> <Dialog :visible.sync="visible" title="default slot" > <!-- The <slot></slot> will be replaced here --> <div class="slot-body">fatfish</div> </Dialog> </div></template><script>import Dialog from './components/dialog.vue'export default { name: 'slot', components: { Dialog, }, data () { return { visible: false } }, methods: { onToggleVisible () { this.visible = !this.visible } }}
不管是开发语言,还是开发框架,都是我们实现创造产品的工具,最终,我们能够实现什么样的效果,做出什么样的产品,都是依赖实现它的人。
作为技术人,多学技术没有错,但是不能为了学习技术而学习技术,我们学习技术的目的,是要解决一些问题,这个是我对学习技术的一些感悟。
当然,也希望我今天分享的内容,对你有用。
本文链接:http://www.28at.com/showinfo-26-18993-0.html都快2024年了,别只使用React,需要学习一下Vue,不然没出路了
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com