日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

div滚动到指定位置 vue_【Vue 进阶】从 slot 到无渲染组件

發布時間:2025/4/17 vue 193 豆豆
生活随笔 收集整理的這篇文章主要介紹了 div滚动到指定位置 vue_【Vue 进阶】从 slot 到无渲染组件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是插槽

插槽(slot)通俗的理解就是“占坑”,在組件模板中占有位置,當使用該組件的時候,可以指定各個坑的內容。也就是我們常說的內容分發

值得一提的是,插槽這個概念并不是 Vue 提出的,而是 web Components 規范草案中就提出的,具體入門可以看 使用 templates and slots[1] ,Vue 只是借鑒了這個思想罷了

在 Vue 2.6.0 中,我們為具名插槽和作用域插槽引入了一個新的統一的語法 (即 v-slot 指令)。它取代了 slot 和 slot-scope,這兩個目前已被廢棄但未被移除且仍在文檔中的 attribute

本文的例子基于 Vue 2.6.X,所以用的都是 v-slot 的語法。

本文 DEMO 已全部放到 Github[2] 和 沙箱[3] 中,供大家學習,如有問題,歡迎評論提出。

默認插槽

我們新建父組件 Parent 和子組件 Child,結構如下:

父組件:


<h3>默認插槽h3>
<Child>
????<div?class="parent-text">Hi,?I?am?from?parent.div>
Child>

子組件:

<div?class="child">
????<slot>slot>
????<div>Hello,?I?am?from?Child.div>
div>

父組件調用 Child 組件的時候,會在 Child 標簽中將內容傳入到子組件中的 標簽中,如下所示

也就是最后的渲染結果如下:

<div?class="child">
????<div?class="parent-text">Hi,?I?am?from?parent.div>
????<div>Hello,?I?am?from?Child.div>
div>

后備內容

我們可以在子組件中的 中加入一些內容,像下面一樣

<div?class="child">
??<slot>當父組件不傳值的時候,我就展示,我只是一個后備軍slot>
??<div>Hello,?I?am?from?Child.div>
div>

當父組件調用的時候, 子組件標簽內沒有相關的內容時候, 標簽內的內容就會生效,否則就不會渲染,可以理解就是個“備胎”

如父組件調用上面子組件:

????
????<h3>后備內容h3>
????<Child1>Child1>

結果如下:

具名插槽

當然,插槽可以不止一個,這個主要是為了能夠靈活的控制插槽的位置以及組件的抽象。我們可以通過在子組件的 slot 標簽中設置 name 屬性,然后在父組件中通過 v-slot:(或者使用簡寫 #) + 子組件 name 屬性值的方式指定要插入的位置。如果是默認插槽的話,v-slot:default 即可

如下父組件:

????
????<h3>具名插槽h3>
????<Child2>
??????<template?v-slot:footer><div>我是底部div>template>
??????<template?#header><div>我是頭部div>template>
??????<template?v-slot:default>
????????<div>我是內容div>
??????template>
????Child2>

子組件

??<div?class="child">
????<slot?name="header">slot>
????<slot>slot>
????<div>Hello,?I?am?from?Child.div>
????<slot?name="footer">slot>
??div>

需要留意的是,最后渲染的順序是以子組件的順序為主,也就是上面的例子,渲染出來如下:

作用域插槽

有時候,我們想在一個插槽中使用子組件的數據和事件,類似如下(注意:user 是定義在 Child3 組件中的數據):

????<Child3>
??????<template>
????????<div>我的名字:{{user.name}}div>
????????<div>我的年齡:{{user.age}}div>
????????<button?@click="callMe">Clicl?Mebutton>
??????template>
????Child3>

會直接報錯:

原因在于父組件取不到子組件的數據,這里記住一個原則:父級模板里的所有內容都是在父級作用域中編譯的;子模板里的所有內容都是在子作用域中編譯的。

那我們怎樣才能獲取到子組件的數據或者事件呢?我們可以直接在子組件中通過 v-bind 的方式將數據或者事件傳遞給父組件中,如下所示

??<div?class="child">
????<div>Hello,?I?am?from?Child.div>
????
????<slot?:user="user"?:callMe="callMe">slot>
??div>

然后在父組件中的插槽內,通過類似 v-slot:default="slotProps" 接受子組件傳遞過來的數據

????<Child3>
??????
??????<template?v-slot:default="slotProps">
????????<div>我的名字:{{slotProps.user.name}}div>
????????<div>我的年齡:{{slotProps.user.age}}div>
????????<button?@click="slotProps.callMe">Clicl?Mebutton>
??????template>
????Child3>

以上 slotProps 可以自定義,而且可以使用解構賦值的語法


<template?v-slot:other="{?user,?callMe}">
??<div>我的名字:{{user.name}}div>
??<div>我的年齡:{{user.age}}div>
??<button?@click="callMe">Clicl?Mebutton>
template>

實例:解耦業務邏輯和視圖

我們經常會遇到一個場景,就是兩個組件的業務邏輯是可以復用的,但是視圖卻不一樣,比如我們經常會有類似切換開關的需求,功能包括:

  • 關閉開關
  • 打開開關
  • 切換開關
  • 開關關閉或者打開的時候不一樣的內容

我們可以很快的寫出它的一個 JS 業務邏輯代碼:

export?default?{
??data()?{
????return?{
??????currentState:?this.state
????}
??},
??props:?{
????state:?{
??????type:?Boolean,
??????default:?false
????}
??},
??methods:?{
????openState()?{
??????this.currentState?=?true;
????},
????closeState()?{
??????this.currentState?=?false;
????},
????toggle()?{
??????this.currentState?=?!this.currentState;
????}
??}
}

但是可能現在我的樣式一是這樣的

然而另外一個地方的樣式是這樣的(只是舉個例子,現實可能更加的復雜,甚至有可能一些按鈕直接就隱藏掉了)

這個時候,插槽就派上了用場。上面提到作用域插槽可以將數據和事件從子組件傳遞給父組件,這就相當于對外暴露了接口。而且可以將 HTML 中的 DOM 以及 CSS 交給父組件(調用方)去維護,子組件通過 標簽插入的位置即可,主要邏輯如下:

子組件:

<template>
??<div?class="toggle-container">
????<slot?:currentState="currentState"?:setOn="openState"?:setOff="closeState"?:toggle="toggle">slot>
??div>
template>

父組件:

<Toggle1?:state="state"?class="toggle-container-two">
??<template?v-slot:default="{currentState,?setOn,?setOff,?toggle?}">
????<button?@click="toggle">切換button>
????<button?@click="setOff">關閉button>
????<button?@click="setOn">打開button>
????<div?v-if="currentState">我是打開的內容div>
????<div?v-else>我是關閉的內容div>
??template>
Toggle1>

我們現在采用的是單文件的方式書寫的,實際上子組件還是會有相關的 HTML 結構,如何做到子組件完全不需要渲染自己的 HTML 呢?那得了解下無渲染組件的實現

進階:無渲染組件的實現

無渲染組件(renderless components)是指一個不需要渲染任何自己的 HTML 的組件。相反,它只管理狀態和行為。它會暴露一個單獨的作用域,讓父組件或消費者完全控制應該渲染的內容。Vue 中,提供了單文件組件的寫法。像上面的示例一樣,我們始終還是在子組件中進行了一些渲染的操作,那如何做到真正的不渲染組件呢?

比如上面的 toggle 例子,我們已經做到了子組件暴露一個單獨的作用域,讓父組件或消費者完全控制應該渲染的內容。現在我們需要將單文件中的 template 結構(slot 標簽外層的 div)完全交給父組件,但單文件組件中 slot 標簽是不能作為 template 的根元素的

這個時候,我們需要了解一下 Vue 渲染函數(render function)

歸根結底,Vue 及其所有的組件都只是 JavaScript。單文件組件最后會被構建工具,如 webpack,將 CSS 抽取形成一個文件,其他的內容會被轉換成 ?JavaScript,類似如下:

export?default?{
??template:?<div?class="mood">...div>,
??data:?()?=>?({?todayIsSunny:?true?})
}

當然,這個不是它的最終形態,模板編譯器會提取 template 屬性內容并將其內容編譯為 JavaScript,然后通過 render 函數添加到組件對象中。最終形態應該是如下:

render(h)?{
??return?h(
????'div',
????{?class:?'mood'?},
????this.todayIsSunny???'Makes?me?happy'?:?'Eh!?Doesn't?bother?me'
??)
}

具體的渲染函數可參見官網[4],雖然寫 render 函數的成本會高一些,但是它的性能會比單文件組件好很多。

以上的例子,只有插槽的時候,我們只需要在 render 函數中,使用 this.$scopedSlots.default 代替掉 標簽即可

代碼如下:

export?const?toggle?=?{
??data()?{
????return?{
??????currentState:?this.state
????}
??},
??render()?{
????return?this.$scopedSlots.default({
??????currentState:?this.currentState,
??????setOn:?this.openState,
??????setOff:?this.closeState,
??????toggle:?this.toggle,
????})
??},
??props:?{
????state:?{
??????type:?Boolean,
??????default:?false
????}
??},
??methods:?{
????openState()?{
??????this.currentState?=?true;
????},
????closeState()?{
??????this.currentState?=?false;
????},
????toggle()?{
??????this.currentState?=?!this.currentState;
????}
??}
}
?

以上就可以做到子組件完全不渲染自己的 HTML了

總結

本文介紹了一些 Vue 插槽的基本知識,包括

  • 默認插槽
  • 后備內容
  • 具名插槽
  • 作用域插槽

然后介紹了一下,如何通過插槽實現業務邏輯和視圖的解耦,再結合渲染函數實現真正的無渲染函數

本文 DEMO 已全部放到 Github[5] 和 沙箱[6] 中,供大家學習,如有問題,可以評論提出。

這么用心了,求個贊,哈哈

希望對大家有所幫助~

往期優秀文章推薦

  • 【Vue進階】——如何實現組件屬性透傳?[7]
  • 前端應該知道的 HTTP 知識【金九銀十必備】[8]
  • 最強大的 CSS 布局 —— Grid 布局[9]
  • 如何用 Typescript 寫一個完整的 Vue 應用程序[10]
  • 前端應該知道的web調試工具——whistle[11]

參考:

  • Vue 插槽(slot)使用(通俗易懂)[12]

  • vue 2.6 中 slot 的新用法[13]

  • (譯)函數式組件在Vue.js中的運用[14]

  • Building “Renderless” Vue Components[15]

參考資料

[1]

使用 templates and slots: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_templates_and_slots

[2]

Github: https://github.com/GpingFeng/vue-slot

[3]

沙箱: https://codesandbox.io/s/hopeful-nash-id826?file=/src/main.js

[4]

官網: https://cn.vuejs.org/v2/guide/render-function.html

[5]

Github: https://github.com/GpingFeng/vue-slot

[6]

沙箱: https://codesandbox.io/s/hopeful-nash-id826?file=/src/main.js

[7]

【Vue進階】——如何實現組件屬性透傳?: https://juejin.im/post/6865451649817640968

[8]

前端應該知道的 HTTP 知識【金九銀十必備】: https://juejin.im/post/6864119706500988935

[9]

最強大的 CSS 布局 —— Grid 布局: https://juejin.im/post/6854573220306255880

[10]

如何用 Typescript 寫一個完整的 Vue 應用程序: https://juejin.im/post/6860703641037340686

[11]

前端應該知道的web調試工具——whistle: https://juejin.im/post/6861882596927504392

[12]

Vue 插槽(slot)使用(通俗易懂): https://juejin.im/post/6844903920037281805

[13]

vue 2.6 中 slot 的新用法: https://juejin.im/post/6844903885476200461

[14]

(譯)函數式組件在Vue.js中的運用: https://juejin.im/post/6844903752164442120

[15]

Building “Renderless” Vue Components: https://css-tricks.com/building-renderless-vue-components/

總結

以上是生活随笔為你收集整理的div滚动到指定位置 vue_【Vue 进阶】从 slot 到无渲染组件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。