[Рекомендуемая коллекция] Более 11 практических навыков, позволяющих легко перейти с Vue на React

внешний интерфейс Vue.js React.js
[Рекомендуемая коллекция] Более 11 практических навыков, позволяющих легко перейти с Vue на React

предисловие

в этот卷神Эпоха, которая вышла массово, просто искуснаVueТолстоголовую рыбу много раз били.Во время интервью его спросили: «Вы не знаете, как реагировать?» Я потерял дар речи и не знал, что сказать.

В этой статье делается попыткаVueНекоторые общие черты вReactреализовать его снова, если вы оказалисьVueПеременаReact,илиReactПеременаVue, с нетерпением жду помощи для вас.

Если вы знакомыReactа такжеVueОдноклассники становятся на колени и просят лёгкого спрея (ручное выживание)

每个功能,都有对应的Vue和React版本实现,也有对应的截图或者录屏

Vue-репозиторий

Реагировать на репозиторий

1. v-if

Давайте начнем с наиболее распространенного отображения и скрытия.Отображение и скрытие элемента в Vue обычно обрабатывается с помощьюv-ifилиv-showинструкции, ноv-ifЯвляется «истинным» условным рендерингом, прослушиватели событий и подкомпоненты внутри условного блока соответствующим образом уничтожаются и перестраиваются во время перехода. а такжеv-showЭто просто, просто управление стилем css.

v-if исходный код нажмите здесь

Vue

<template>
  <div class="v-if">
    <button @click="onToggleShow">切换</button>
    <div v-if="isShow">前端胖头鱼 显示出来啦</div>
  </div>
</template>

<script>
export default {
  name: 'vif',
  data () {
    return {
      isShow: true
    }
  },
  methods: {
    onToggleShow () {
      this.isShow = !this.isShow
    }
  }
}
</script>

React

исходный код vif нажмите здесь

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 }>切换</button>
      {/* 也可以用三目运算符 */}
      {/* { isShow ? <div>前端胖头鱼 显示出来啦</div> : null } */}
      {
        isShow && <div>前端胖头鱼 显示出来啦</div>
      }
    </div>
  )
}

предварительный просмотр

v-if.gif

2. v-show

Так же, на этот раз мы проходимv-showДля достижения функции отображения и скрытия при наблюдении за изменениями стиля DOM.

Уведомление:Почему здесь не отображается?blockЭто связано с тем, что некоторые элементы сами по себе не являются элементами блочного уровня, если их принудительно установить вblockМожно вызвать неправильный стиль.

Vue

Исходный код V-шоу Нажмите здесь

<template>
  <div class="v-show">
    <button @click="onToggleShow">切换</button>
    <div v-show="isShow">前端胖头鱼 显示出来啦</div>
  </div>
</template>

<script>
export default {
  name: 'vshow',
  data () {
    return {
      isShow: true
    }
  },
  methods: {
    onToggleShow () {
      this.isShow = !this.isShow
    }
  }
}
</script>


React

исходный код vShow нажмите здесь

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 }>切换</button>
      {
        <div style={{ display: isShow ? '' : 'none' }}>前端胖头鱼 显示出来啦</div>
      }
    </div>
  )
}


предварительный просмотр

v-show.gif

3. v-for

В общем, рендеринг списка вVueиспользуется вv-forдиректива, необходимо использовать директиву v-foritem in itemsспециальный синтаксис формы, гдеitemsмассив исходных данных, аitemявляется псевдонимом элемента массива, по которому выполняется итерация. Конечно, каждому элементу нужно задать уникальныйkey

Vue

v-для исходного кода нажмите здесь

<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: '前端',
        },
        {
          id: 2,
          name: '后端',
        },
        {
          id: 3,
          name: 'android',
        },
        {
          id: 4,
          name: 'ios',
        },
      ]
    }
  }
}
</script>

React

существуетReactнетv-forинструкция, мы можем использоватьmapМетод обхода выполняет аналогичные функции

vДля получения исходного кода нажмите здесь

import React, { useState } from "react"

export default function VFor (){
  const [ list, setList ] = useState([
    {
      id: 1,
      name: '前端',
    },
    {
      id: 2,
      name: '后端',
    },
    {
      id: 3,
      name: 'android',
    },
    {
      id: 4,
      name: 'ios',
    },
  ])

  return (
    <div className="v-for">
      {
        list.map((item) => {
          return <div className="v-for-item" key={ item.id }>{ item.name }</div>
        })
      }
    </div>
  )
}


предварительный просмотр

v-for.png

4. computed

Вычисляемые свойства удобны, когда переменная должна быть оценена в зависимости от других переменных, иVueВычисляемые свойства кэшируются на основе их зависимых зависимостей, а значение зависимости не изменилось и не будет пересчитываться для достижения эффекта кэширования.

Давайте рассмотрим простой пример сложения:num3Зависит отnum1а такжеnum2Добавьте результат, пока кнопка нажата один разnum1добавить 10,num3будет продолжать добавлять 10

Vue

вычисленный исходный код нажмите здесь

<template>
  <div class="computed">
    <button @click="onAdd">+10</button>
    <div>计算结果:{{ 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

ReactЗдесь нет вычисляемых свойств, но мы можем передатьuseMemoэтот хук для реализации, иVueРазница в том, что мы должны вычислитьРучное обслуживание зависимостей

вычисленный исходный код нажмите здесь

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>计算结果:{ num3 }</div>
    </div>
  )
}


предварительный просмотр

computed.gif

5. watch

Иногда нам нужно отслеживать изменения данных, а затем выполнять асинхронное поведение или дорогостоящие операции, которые можно использовать в Vue.watchреализовать

Давайте смоделируем такой сценарий и передадимwatchДля достижения: выберитеboyилиgirl, выбрав его, отправьте запрос и отобразите результат запроса. (Здесь процесс асинхронного запроса моделируется через setTimeout)

Vue

посмотреть исходный код нажмите здесь

<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 ? '请求中' : `请求结果: 选中${this.selectValue || '~'}`
    }
  },
  watch: {
    selectValue () {
      this.fetch()
    }
  },
  methods: {
    onSelect (value) {
      this.selectValue = value  
    },
    fetch () {
      if (!this.fetching) {
        this.fetching = true

        setTimeout(() => {
          this.fetching = false
        }, 1000)
      }
    }
  }
}
</script>

React

ReactЧтобы реализовать действие по мониторингу некоторых изменений данных и выполнению ответа, вы можете использоватьuseEffect

посмотреть исходный код нажмите здесь

import React, { useState, useMemo, useEffect } from "react"
import './watch.css'

export default function Watch() {
  const [fetching, setFetching] = useState(false)
  const [selects, setSelects] = useState([
    'boy',
    'girl'
  ])
  const [selectValue, setSelectValue] = useState('')

  const result = useMemo(() => {
    return fetching ? '请求中' : `请求结果: 选中${selectValue || '~'}`
  }, [ fetching ])

  const onSelect = (value) => {
    setSelectValue(value)
  }
  const fetch = () => {
    if (!fetching) {
      setFetching(true)

      setTimeout(() => {
        setFetching(false)
      }, 1000)
    }
  }

  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>
  )
}


предварительный просмотр

watch.gif

6. style

Иногда динамическое добавление стилей к элементам неизбежно.style,Vueа такжеReactВсе они предоставляют нам удобный способ использования.

В основном то же самое в использовании:

Тот же пункт:

Имена свойств CSS могут быть названы в CamelCase или разделены тире (кебаб-регистр, не забудьте заключить их в кавычки)

разница:

  1. Vue может связывать несколько объектов стиля с помощью синтаксиса массива, React в основном имеет форму одного объекта (это также может быть сделано Vue)
  2. React автоматически добавит «px» (Vue не обрабатывает это автоматически) добавляется к свойству, встроенный стиль которого является числом, другие единицы измерения необходимо указывать вручную.
  3. Стили React не автозаполняют префиксы. Для поддержки старых браузеров необходимо вручную добавить соответствующие атрибуты стиля. В Vue, когда v-bind:style использует свойство CSS, для которого требуется префикс движка браузера, например, преобразование, Vue.js автоматически обнаружит и добавит соответствующий префикс.

Vue

исходный код стиля нажмите здесь

<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>

React

исходный код стиля нажмите здесь

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>
  )
}

предварительный просмотр

style.png

7. class

Как динамически добавлять классы к элементам? Во Vue я предпочитаю использовать синтаксис массивов (и, конечно, способ записи объектов), а в React можно использовать и некоторые сторонние пакеты, напримерclassnamesЭто упрощает добавление классов.

Давайте посмотрим, как добиться эффекта выбора кнопки без использования какой-либо библиотеки.

Vue

исходный код класса нажмите здесь

<template>
  <button :class="buttonClasses" @click="onClickActive">{{ buttonText }}</button>
</template>

<script>
export default {
  name: 'class',
  data () {
    return {
      isActive: false,
    }
  },
  computed: {
    buttonText () {
      return this.isActive ? '已选中' : '未选中'
    },
    buttonClasses () {
	  // 通过数组形式维护class动态列表 		
      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>

React

исходный код класса нажмите здесь

import React, { useMemo, useState } from "react"

import './class.css' // 此处样式与上面是一样的


export default function Class (){
  const [ isActive, setIsActive ] = useState(false)
  const buttonText = useMemo(() => {
    return isActive ? '已选中' : '未选中'
  }, [ isActive ])
  const buttonClass = useMemo(() => {
    // 和Vue中不太一样的是我们需要手动join一下,变成'button active'形式
    return [ 'button', isActive ? 'active' : '' ].join(' ')
  }, [ isActive ])

  const onClickActive = () => {
    setIsActive(!isActive)
  }

  return (
    <div className={ buttonClass } onClick={onClickActive}>{ buttonText }</div>
  )
}

предварительный просмотр

class.gif

8.provide/inject

И у Vue, и у React есть свои хорошие решения для управления глобальным состоянием, например, в Vue.Vuex, в реакцииreduxа такжеMobx, конечно внедряя их в небольшие проектыИзлишествоТеперь есть ли другое решение?

Доступно в Vueprovide/inject

В React вы можете использоватьContext

假设全局有有一个用户信息userInfo的变量,需要在各个组件中都能便捷的访问到,在Vue和React中该如何实现呢?

Vue

Vueзаимствовано изprovide/injectСостояние верхнего уровня может быть передано любому дочернему узлу, если мы объявим новый в app.vue.userInfoданные

предоставить исходный код нажмите здесь

app.vue


<template>
  <div id="app">
    <div class="title">我是Vue栗子</div>
    <router-view/>
  </div>
</template>
<script>

export default {
  name: 'app',
  // 声明数据	
  provide () {
    return {
      userInfo: {
        name: '前端胖头鱼'
      }
    }
  }
}
</script>

provide.vue

<template>
  <div class="provide-inject">{{ userInfo.name }}</div>
</template>

<script>
export default {
  name: 'provideInject',
  // 使用数据
  inject: [ 'userInfo' ]
}
</script>

React

ReactДля достижения аналогичной функции вContext, поделиться глобальным состоянием с любым дочерним узлом

предоставить исходный код нажмите здесь

context/index.js

import { createContext } from "react";

export const UserInfoContext = createContext({
  userInfo: {
    name: ''
  }
})

app.js

import { UserInfoContext } from './context/index'

function App() {
  return (
    <BrowserRouter>
      // 注意这里
      <UserInfoContext.Provider
        value={{ userInfo: { name: '前端胖头鱼' } }}
      >
        <div className="title">我是React栗子</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>
  );
}

provide.js

import React, { useContext } from "react"
import { UserInfoContext } from '../context/index'


export default function Provide() {
  // 通过userContext,使用定义好的UserInfoContext
  const { userInfo } = useContext(UserInfoContext)

  return (
    <div class="provide-inject">{ userInfo.name }</div>
  )
}


предварительный просмотр

4127923929-provide.png

9. слот (слот по умолчанию)

слотVueЭто очень практичная функция в默认坑位,具名坑位,作用域坑位, давайте рассмотрим практический примерReactкак добиться той же функциональности.

Предположим, мы хотим реализовать простуюdialogКомпонент, основная функция заключается в том, что заголовок может передавать строку, а контентная часть может быть полностью настроена, как это должно быть реализовано?

默认插槽.gif

Vue

исходный код слота нажмите здесь

dialog

<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">
		// 注意这里放了一个默认插槽坑位
        <slot></slot>
      </div>
      <div class="dialog-footer">
        <div class="button-cancel" @click="onHide">取消</div>
        <div class="button-confirm" @click="onHide">确定</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>

slot

<template>
  <div class="slot">
    <button @click="onToggleVisible">切换dialog</button>
    <Dialog
      :visible.sync="visible"
      title="默认插槽"
    >
	  // 这里会替换到<slot></slot>的位置处
	  <div class="slot-body">前端胖头鱼</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
    }
  }
}

React

Что я должен сделать, чтобы добиться той же функции в React?ReactНо слота нет! не волнуйся, хотяReactНет понятия слотов вprops.childrenПолучить дочерние элементы внутри компонента, через которые можно реализовать функцию слота по умолчанию

исходный код слота нажмите здесь

Dialog

import React, { useState, useEffect } from "react"

import './dialog.css'

export default function Dialog(props) {
  // 原谅我用visible -1这种傻叉的方式先实现了, 重点不是在这里
  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" onClick={ onHide }></div>
      <div className="dialog-body">
        { title ? <div className="dialog-title">{ title }</div> : null }
        <div className="dialog-main">
          {/* 注意这里,通过children实现默认插槽功能 */}
          {children}
        </div>
        <div className="dialog-footer">
          <div className="button-cancel" onClick={ onHide }>取消</div>
          <div className="button-confirm" onClick={ onHide }>确定</div>
        </div >
      </div >
    </div >
  )
}

slot

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 }>切换dialog</button>
      <Dialog
        visible={visible}
        title="默认插槽"
      >
        {/* 注意这里,会被Dialog组件的children读取并且替换掉 */}
        <div className="slot-body">前端胖头鱼</div>
      </Dialog>
    </div>
  )
}


предварительный просмотр

默认插槽.gif

10. слот имени

Когда внутри компонента есть несколько динамических элементов, которые необходимо заполнить извне, слота по умолчанию недостаточно, нам нужно предоставить слотвзять имя, так что снаружи можно "шаг за шагом" в назначенное место.

Давайте обогатимсяDialogкомпоненты, предполагаяtitleМожет ли он также поддерживать динамическую доставку контента?

Vue

Через во Vue<slot name="main"></slot>Форма сначала объявляет слот, а затем проходитv-slot:mainВ виде употребления будет засыпана одна редька и одна косточка.

исходный код nameSlot нажмите здесь

Преобразование диалога

<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>
      <!-- 注意这里,没有传title属性,时候通过插槽进行内容承接 -->
      <slot name="title" v-else></slot>
      <div class="dialog-main">
        <!-- 声明main部分 -->
        <slot name="main"></slot>
      </div>
      <div class="dialog-footer">
        <div class="button-cancel" @click="onHide">取消</div>
        <div class="button-confirm" @click="onHide">确定</div>
      </div>
    </div>
  </div>
</template>
// ... 其他地方和上面试一样的

nameSlot

<template>
  <div class="slot">
    <button @click="onToggleVisible">切换dialog</button>
    <Dialog
      :visible.sync="visible"
    >
      <template v-slot:title>
        <div class="dialog-title">具名插槽</div>
      </template>
      <template v-slot:main>
        <div class="slot-body">前端胖头鱼</div>
      </template>
    </Dialog>
  </div>
</template>

<script>
import Dialog from './components/dialog.vue'

export default {
  name: 'nameSlot',
  components: {
    Dialog,
  },
  data () {
    return {
      visible: false
    }
  },
  methods: {
    onToggleVisible () {
      this.visible = !this.visible
    }
  }
}
</script>

React

проходить впередиprops.childrenАтрибуты могут считывать содержимое тега компонента иVueСлоты по умолчанию делают то же самое, но как это делают именованные слоты?ReactОдна из забавных вещей, я думаю, что вы можете передавать атрибуты и что угодно,字符串,数字,函数,连DOMтакже может передаваться. Следовательно, также очень просто реализовать именованный слот, и его можно передать напрямую как свойство.

исходный код nameSlot нажмите здесь

Преобразование диалога

import React, { useState, useEffect } from "react"

import './dialog.css'

export default function Dialog(props) {
  // 原谅我用visible -1这种傻叉的方式先实现了, 重点不是在这里
  const { title, main, 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" onClick={ onHide }></div>
      <div className="dialog-body">
        {/* { title ? <div className="dialog-title">{ title }</div> : null } */}
        {/* 注意这里,直接渲染title就可以了 */}
        { title }
        <div className="dialog-main">
          {/* 注意这里,通过children实现默认插槽功能 */}
          {/* {children} */}
          {/* 这一这里不是children了,是main */}
          { main }
        </div>
        <div className="dialog-footer">
          <div className="button-cancel" onClick={ onHide }>取消</div>
          <div className="button-confirm" onClick={ onHide }>确定</div>
        </div >
      </div >
    </div >
  )
}


nameSlot

import React, { useState } from "react"
import Dialog from './components/dialog'

import './slot.css'

export default function NameSlot() {
  const [visible, setVisible] = useState(-1)

  const onToggleVisible = () => {
    setVisible(Math.random())
  }

  return (
    <div className="slot">
      <button onClick={ onToggleVisible }>切换dialog</button>
      <Dialog
        visible={visible}
        // 注意这里,直接传递的DOM
        title={ <div className="dialog-title">默认插槽</div> }
        // 注意这里,直接传递的DOM
        main={ <div className="slot-body">前端胖头鱼</div> }
      >
      </Dialog>
    </div>
  )
}

предварительный просмотр

Именованные слоты можно увидеть,ReactБолее лаконично использовать атрибуты напрямую

具名插槽.gif

11. слот для прицела

имеют默认插槽,具名插槽Наконец, конечно же, слот для прицела незаменим! Иногда бывает полезно, чтобы содержимое слота имело доступ к данным, которые существуют только в дочерних компонентах, в чем суть слотов с ограниченной областью действия.

Предполагать:DialogВнутри компонента естьuserInfo: { name: '前端胖头鱼' }объект данных, хотите использоватьDialogДоступ к внешнему слоту компонента тоже есть, что делать?

Vue

Исходный код scopeSlot нажмите здесь

Dialog

<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>
      <!-- 注意这里,通过绑定userInfo外部可以进行使用 -->
      <slot name="title" :userInfo="userInfo" v-else></slot>
      <div class="dialog-main">
	    <!-- 注意这里,通过绑定userInfo外部可以进行使用 -->
        <slot name="main" :userInfo="userInfo"></slot>
      </div>
      <div class="dialog-footer">
        <div class="button-cancel" @click="onHide">取消</div>
        <div class="button-confirm" @click="onHide">确定</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "dialog",
  // ...
  data () {
    return {
      userInfo: {
        name: '前端胖头鱼'
      }
    }
  },
  // ...	
};
</script>

scopeSlot

<template>
  <div class="slot">
    <button @click="onToggleVisible">切换dialog</button>
    <Dialog
      :visible.sync="visible"
    >
      <template v-slot:title>
        <div class="dialog-title">作用域插槽</div>
      </template>
      <!-- 注意这里 -->
      <template v-slot:main="{ userInfo }">
        <!-- 注意这里userInfo是Dialog组件内部的数据 -->
        <div class="slot-body">你好{{ userInfo.name }}</div>
      </template>
    </Dialog>
  </div>
</template>

React

В том же предложении можно передать все в React.Подобно реализации именованных слотов, мы передаем DOM напрямую.Точно так же мы можем передавать функции для передачиDialogвнутри компонентаuserInfoДанные передаются во внешнее использование параметрами функции

Исходный код scopeSlot нажмите здесь

Преобразование диалога

import React, { useState, useEffect } from "react"

import './dialog.css'

export default function Dialog(props) {
  // 原谅我用visible -1这种傻叉的方式先实现了, 重点不是在这里
  const { title, main, visible = -1 } = props
  const [visibleInner, setVisibleInner] = useState(false)
  const [ userInfo ] = useState({
    name: '前端胖头鱼'
  })

  const onHide = () => {
    setVisibleInner(false)
  }

  useEffect(() => {
    setVisibleInner(visible > 0)
  }, [ visible ])

  return (
    <div className="dialog" style={ { display: visibleInner ? 'block' : 'none' }}>
      <div className="dialog-mask" onClick={ onHide }></div>
      <div className="dialog-body">
        {/* 作用域插槽,当函数使用,并且把数据传递进去 */}
        { title(userInfo) }
        <div className="dialog-main">
          {/* 作用域插槽,当函数使用,并且把数据传递进去 */}
          { main(userInfo) }
        </div>
        <div className="dialog-footer">
          <div className="button-cancel" onClick={ onHide }>取消</div>
          <div className="button-confirm" onClick={ onHide }>确定</div>
        </div >
      </div >
    </div >
  )
}

scopeSlot

import React, { useState } from "react"
import Dialog from './components/dialog'

import './slot.css'

export default function ScopeSlot() {
  const [visible, setVisible] = useState(-1)

  const onToggleVisible = () => {
    setVisible(Math.random())
  }

  return (
    <div className="slot">
      <button onClick={ onToggleVisible }>切换dialog</button>
      <Dialog
        visible={visible}
		// 通过函数来实现插槽
        title={ () => <div className="dialog-title">作用域插槽</div> }
		// 接收userInfo数据
        main={ (userInfo) => <div className="slot-body">你好{ userInfo.name }</div> }
      >
      </Dialog>
    </div>
  )
}


предварительный просмотр

作用域插槽.gif