带你跳出DIV内overflow:scroll的坑

本文探讨了解决网页弹窗滚动时出现的卡顿问题及背景页面跟随滚动的问题。通过使用CSS3的-webkit-overflow-scrolling: touch属性,实现了平滑滚动效果,提升了用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


中秋放假的前夕,给overflow这个属性调戏的体无完肤。

需求是这样的,在弹窗页面上实现滚动的效果。一开始,以为随时秒杀这个需求,不就是一个overflow:scroll就能解决的问题吧。so easy。

谁知道,出现的效果是滚动弹窗页,后面的页面也会随着滚动。并且出现了卡顿的现象。

这很无解。然后尝试了visible这个值。完美呈现想要的效果!

但是,还存在问题。就是滑动卡顿。不会像body的scroll那么平滑!简单的说,就是你滑多少就动多少。特别是在移动设备上,非常差的体验。

CSS3 的 -webkit-overflow-scrolling: touch 可以让页面在Native端滚动时模拟原生的弹性滚动效果。

完美还原滚动效果!

<script setup> // import { h } from &#39;snabbdom&#39; import { onBeforeUnmount, ref, shallowRef } from &#39;vue&#39; // import { IButtonMenu } from &#39;@wangeditor/core&#39; import { Boot } from &#39;@wangeditor/editor&#39; import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; // 测试:第三方插件 // import withCtrlEnter from &#39;@wangeditor/plugin-ctrl-enter&#39; // Boot.registerPlugin(withCtrlEnter) // // 测试:多语言 // i18nChangeLanguage(&#39;en&#39;) // // 测试:注册 renderElem // function renderElemFn(elem, children) { // const vnode = h(&#39;div&#39;, {}, children) // type: &#39;paragraph&#39; 节点,即渲染为 <p> 标签 // return vnode // } // const renderElemConf = { // type: &#39;paragraph&#39;, // 节点 type ,重要!!! // renderElem: renderElemFn, // } // Boot.registerRenderElem(renderElemConf) // // 测试:注册插件 // function withCtrlEnter(editor) { // const { insertBreak } = editor // setTimeout(() => { // // beforeInput 事件不能识别 ctrl+enter ,所以自己绑定 DOM 事件 // const { $textArea } = DomEditor.getTextarea(newEditor) // $textArea.on(&#39;keydown&#39;, e => { // const isCtrl = e.ctrlKey || e.metaKey // if (e.keyCode === 13 && isCtrl) { // // ctrl+enter 触发换行 // editor.insertBreak() // } // }) // }) // const newEditor = editor // newEditor.insertBreak = () => { // const e = window.event // const isCtrl = e.ctrlKey || e.metaKey // // 只有 ctrl 才能换行 // if (isCtrl) { // insertBreak() // } // } // return newEditor // } // Boot.registerPlugin(withCtrlEnter) // 测试:注册 button menu // class MyButtonMenu { // constructor() { // // this.title = &#39;&#39;, // this.tag = &#39;button&#39; // } // getValue() { return &#39;&#39; } // isActive() { return false } // isDisabled() { return false } // exec(editor) { // console.log(editor) // // alert(&#39;menu1 exec&#39;) // } // } // const menuConf = { // key: &#39;my-menu-1&#39;, // menu key ,唯一。注册之后,需通过 toolbarKeys 配置到工具栏 // factory() { // return new MyButtonMenu() // }, // } // // 检查菜单是否已注册,避免重复注册 // if (!Boot.getMenuConfig(&#39;my-menu-1&#39;)) { // Boot.registerMenu(menuConf); // console.log(&#39;菜单注册成功&#39;); // } else { // console.log(&#39;菜单已存在,跳过注册&#39;); // } // console.log(1111111111) // 移到组件最外层,确保模块加载时只执行一次 class MyButtonMenu { constructor() { this.title = &#39;&#39;; // 必须有标题,否则按钮不显示 this.tag = &#39;button&#39;; } getValue() { return &#39;&#39;; } isActive() { return false; } isDisabled() { return false; } exec(editor) { // console.log(&#39;自定义菜单点击&#39;, editor); // editor.insertText(&#39;这是自定义菜单插入的内容&#39;); // 示例功能 } } const menuConf = { key: &#39;my-menu-1&#39;, factory() { return new MyButtonMenu(); }, }; // 核心:用try-catch捕获重复注册错误 try { Boot.registerMenu(menuConf); console.log(&#39;菜单注册成功&#39;); } catch (err) { if (err.message.includes(&#39;Duplicated key&#39;)) { console.log(&#39;菜单已注册,跳过重复注册&#39;); } else { console.error(&#39;菜单注册失败:&#39;, err); } } // 编辑器实例,必须用 shallowRef ,重要! const editorRef = shallowRef() // 内容 HTML const valueHtml = ref(&#39;<p>hello world</p>&#39;) // 编辑器配置 const editorConfig = { placeholder: &#39;请输入内容...&#39;, MENU_CONF: { insertImage: { checkImage(src) { console.log(&#39;image src&#39;, src) if (src.indexOf("http") !== 0) { return "图片网址必须以 http/https 开头"; } return true; }, }, } } // 工具栏配置 const toolbarConfig = { // toolbarKeys: [&#39;headerSelect&#39;, &#39;bold&#39;, &#39;my-menu-1&#39;], // excludeKeys: [], insertKeys: { index: 0, keys: &#39;my-menu-1&#39; } } // 编辑器回调函数 const handleCreated = (editor) => { console.log("created", editor); editorRef.value = editor // 记录 editor 实例,重要! // window.editor = editor // 临时测试使用,用完删除 } const handleChange = (editor) => { console.log("change:", editor.children); } const handleDestroyed = (editor) => { console.log(&#39;destroyed&#39;, editor) } const handleFocus = (editor) => { console.log(&#39;focus&#39;, editor) } const handleBlur = (editor) => { console.log(&#39;blur&#39;, editor) } const customAlert = (info, type) => { alert(`【自定义提示】${type} - ${info}`) } const customPaste = (editor, event, callback) => { console.log(&#39;ClipboardEvent 粘贴事件对象&#39;, event) // 自定义插入内容 editor.insertText(&#39;xxx&#39;) // 返回值(注意,vue 事件的返回值,不能用 return) callback(false) // 返回 false ,阻止默认粘贴行为 // callback(true) // 返回 true ,继续默认的粘贴行为 } // 及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return // 销毁,并移除 editor editor.destroy() }) const getHtml = () => { const editor = editorRef.value if (editor == null) return console.log(editor.getHtml()) } </script> <template> <!-- <div>--> <!-- <button @click="getHtml">获取 html</button>--> <!-- </div>--> <!-- <div style="border: 1px solid #ccc">--> <!-- <!– 工具栏 –>--> <!-- <Toolbar--> <!-- :editor="editorRef"--> <!-- :defaultConfig="toolbarConfig"--> <!-- style="border-bottom: 1px solid #ccc"--> <!-- />--> <!-- <!– 编辑器 –>--> <!-- <Editor--> <!-- v-model="valueHtml"--> <!-- :defaultConfig="editorConfig"--> <!-- @onChange="handleChange"--> <!-- @onCreated="handleCreated"--> <!-- @onDestroyed="handleDestroyed"--> <!-- @onFocus="handleFocus"--> <!-- @onBlur="handleBlur"--> <!-- @customAlert="customAlert"--> <!-- @customPaste="customPaste"--> <!-- style="height: 500px"--> <!-- />--> <!-- </div>--> <div class="editor-container"> <!-- 添加容器类名 --> <!-- 工具栏 --> <Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" style="border-bottom: 1px solid #e5e7eb" /> <!-- 编辑器 --> <Editor v-model="valueHtml" :defaultConfig="editorConfig" @onChange="handleChange" @onCreated="handleCreated" @onDestroyed="handleDestroyed" @onFocus="handleFocus" @onBlur="handleBlur" @customAlert="customAlert" @customPaste="customPaste" /> </div> </template> <style src="@wangeditor/editor/dist/css/style.css"> /* 编辑器整体容器 */ .editor-container { border: 1px solid #e5e7eb; /* 浅灰色边框 */ border-radius: 8px; /* 圆角 */ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 轻微阴影 */ overflow: hidden; /* 防止内部元素溢出 */ transition: box-shadow 0.2s ease; /* 阴影过渡效果 */ } .editor-container:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); /* hover时增强阴影 */ } /* 工具栏样式 */ .w-e-toolbar { background-color: #f9fafb !important; /* 工具栏背景色 */ border-bottom: 1px solid #e5e7eb !important; /* 底部边框 */ padding: 8px 12px !important; /* 内边距 */ } /* 工具栏按钮通用样式 */ .w-e-toolbar .w-e-menu { margin: 0 3px !important; /* 按钮间距 */ border-radius: 4px !important; /* 按钮圆角 */ transition: all 0.2s ease !important; /* 过渡效果 */ } .w-e-toolbar .w-e-menu:hover { background-color: #eef2f5 !important; /* 悬停背景色 */ transform: translateY(-1px) !important; /* 轻微上浮效果 */ } /* 自定义菜单按钮样式(my-menu-1) */ .w-e-toolbar [data-key="my-menu-1"] { background-color: #4f46e5 !important; /* 紫色背景(突出自定义按钮) */ color: white !important; /* 白色文字 */ border: none !important; } .w-e-toolbar [data-key="my-menu-1"]:hover { background-color: #4338ca !important; /* 深色hover效果 */ } /* 编辑区域样式 */ .w-e-text-container { height: 500px !important; /* 固定高度 */ padding: 16px !important; /* 内边距 */ background-color: white !important; /* 白色背景 */ } /* 编辑区域内容样式 */ .w-e-text-container p { margin: 0 0 12px 0 !important; /* 段落间距 */ line-height: 1.8 !important; /* 行高(提升可读性) */ font-size: 14px !important; /* 基础字体大小 */ color: #1f2937 !important; /* 文字颜色 */ } /* 编辑区域聚焦样式 */ .w-e-text-container:focus-within { outline: 2px solid rgba(79, 70, 229, 0.2) !important; /* 聚焦时边框高亮 */ } /* 工具栏分割线样式 */ .w-e-toolbar .w-e-separator { background-color: #e5e7eb !important; /* 分割线颜色 */ margin: 0 6px !important; /* 分割线间距 */ } /* 响应式调整(小屏幕适配) */ @media (max-width: 768px) { .editor-container { border-radius: 4px; /* 小屏幕减小圆角 */ } .w-e-toolbar { padding: 4px 8px !important; /* 小屏幕减小内边距 */ } .w-e-text-container { height: 400px !important; /* 小屏幕减小编辑区高度 */ padding: 12px !important; } } </style>改一改让工具栏悬浮在上面,不会随着页面移动,不论页面滚轮怎么移动都保持在页面上方,右侧添加滚轮使页面可以移动,工具栏上面再搞一个头部,最左边是返回键,中间是AI笔记的标题,最右边是一个头像,点击头像会跳转到个人用户管理界面,头像左边有一个历史记录按钮,点击后会显示一个侧边栏,里面有AI笔记历史,历史记录先留一个按钮就行,头像也先留一个位置就行
最新发布
07-26
<think>我们有一个需求:在Vue项目中使用wangEditor,并实现以下功能: 1. 固定顶部工具栏:当页面滚动时,工具栏始终固定在顶部。 2. 自定义头部:在页面顶部添加一个头部区域,包含返回按钮、标题、历史记录按钮和用户头像。 3. 支持页面滚动和侧边栏显示。 分析: 1. wangEditor的工具栏固定:wangEditor默认工具栏是随着编辑器一起滚动的。要实现固定,我们可以将工具栏单独提取出来,并设置为固定定位(fixed或sticky)。 2. 自定义头部:我们需要在编辑器上方添加一个自定义的头部区域,同样固定定位,这样在滚动时头部和工具栏都会固定在顶部。 3. 侧边栏和滚动条:侧边栏可能是与编辑器并排的布局,我们可以使用flex布局来实现。 步骤: 1. 创建Vue组件,引入wangEditor。 2. 在组件中,我们将编辑器分为两部分:工具栏和编辑区域。通过wangEditor的配置,我们可以分离工具栏和编辑区域。 3. 使用CSS将工具栏和自定义头部固定到顶部。 4. 设置编辑区域的高度,并确保其可以滚动。 5. 实现侧边栏布局。 注意:wangEditor v5版本支持分离工具栏。 参考wangEditor文档:https://www.wangeditor.com/v5/for-frame.html#vue 具体实现: 1. 安装wangEditor: ```bash npm install @wangeditor/editor @wangeditor/editor-for-vue # 或 yarn add @wangeditor/editor @wangeditor/editor-for-vue ``` 2. 创建组件(例如:`RichTextEditor.vue`): ```vue <template> <div class="editor-container"> <!-- 自定义头部 --> <div class="custom-header"> <button class="back-button">返回</button> <div class="title">标题</div> <button class="history-button">历史记录</button> <div class="user-avatar"> <img src="path/to/avatar.jpg" alt="用户头像"> </div> </div> <!-- 工具栏 --> <div ref="toolbarRef" style="background-color: #f1f1f1;"></div> <!-- 编辑区域 --> <div ref="editorRef" style="height: calc(100vh - 120px);"></div> <!-- 侧边栏(根据需求添加内容) --> <div class="sidebar"> <!-- 侧边栏内容 --> </div> </div> </template> <script> import &#39;@wangeditor/editor/dist/css/style.css&#39; // 引入 css import { onBeforeUnmount, onMounted, ref, shallowRef } from &#39;vue&#39; import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; export default { components: { Editor, Toolbar }, setup() { // 编辑器实例,必须用 shallowRef const editorRef = ref(null) const toolbarRef = ref(null) const editor = shallowRef(null) // 模拟数据 const valueHtml = ref(&#39;<p>hello</p>&#39;) // 配置 const editorConfig = { placeholder: &#39;请输入内容...&#39;, // 其他配置... } // 组件挂载时 onMounted(() => { // 创建编辑器 editor.value = new Editor({ selector: editorRef.value, html: valueHtml.value, config: editorConfig, mode: &#39;default&#39;, // 或 &#39;simple&#39; }) // 创建工具栏 const toolbar = new Toolbar({ editor: editor.value, selector: toolbarRef.value, config: { // 工具栏配置 } }) }) onBeforeUnmount(() => { // 组件销毁时,销毁编辑器 editor.value.destroy() }) return { editorRef, toolbarRef, valueHtml, } } } </script> <style> .editor-container { display: flex; flex-direction: column; height: 100vh; position: relative; } .custom-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; padding: 10px; background-color: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .back-button, .history-button { padding: 5px 10px; background: #eee; border: none; cursor: pointer; } .title { flex: 1; text-align: center; font-weight: bold; } .user-avatar img { width: 30px; height: 30px; border-radius: 50%; } /* 工具栏固定 */ #toolbar-container { position: sticky; top: 50px; /* 根据自定义头部的高度调整 */ z-index: 99; background-color: white; } /* 侧边栏布局 */ .editor-container { display: flex; } .sidebar { width: 200px; background: #f8f8f8; height: calc(100vh - 120px); /* 减去头部和工具栏的高度 */ overflow-y: auto; } /* 编辑区域和工具栏区域 */ .editor-main { flex: 1; display: flex; flex-direction: column; } /* 调整结构,将工具栏和编辑区域放在一个容器中,侧边栏在另一边 */ </style> ``` 但是,上面的代码中,工具栏和编辑区域是分离的,但是侧边栏和编辑区域是并排的。我们需要调整结构: 修改模板: ```vue <template> <div class="editor-layout"> <!-- 自定义头部 --> <div class="custom-header"> <!-- ... --> </div> <div class="main-content"> <!-- 侧边栏 --> <div class="sidebar"> <!-- 侧边栏内容 --> </div> <div class="editor-container"> <!-- 工具栏 --> <div ref="toolbarRef" class="toolbar-container"></div> <!-- 编辑区域 --> <div ref="editorRef" class="editor-content"></div> </div> </div> </div> </template> <style> .editor-layout { display: flex; flex-direction: column; height: 100vh; } .custom-header { position: sticky; top: 0; z-index: 100; /* ... 同上 ... */ } .main-content { display: flex; flex: 1; overflow: hidden; } .sidebar { width: 200px; background: #f8f8f8; overflow-y: auto; } .editor-container { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .toolbar-container { position: sticky; top: 50px; /* 根据自定义头部的高度,如果头部高度是50px,则这里设置top:50px */ z-index: 99; background-color: white; } .editor-content { flex: 1; overflow-y: auto; padding: 10px; } </style> ``` 注意: 1. 自定义头部固定,所以使用`position: sticky; top:0;` 2. 工具栏也要固定,但位置应该在头部下方,所以设置`top: 头部高度`(假设头部高度为50px,则设置`top:50px`) 3. 编辑区域需要设置高度,并且可以滚动。 这样,当页面滚动时,头部和工具栏都会固定在顶部,编辑区域和侧边栏可以滚动。 但是,如果侧边栏内容很长,也需要滚动,我们可以给侧边栏设置`overflow-y: auto;`。 另外,需要根据实际头部高度调整工具栏的top值。 3. 关于历史记录按钮的功能:这需要你自己实现历史记录逻辑(比如记录编辑内容的变化),可以使用wangEditor的onChange事件来记录内容变化。 4. 返回按钮、用户头像等功能需要根据实际项目需求实现。 5. 注意:由于工具栏和编辑区域分离,我们需要确保在销毁组件时,同时销毁工具栏和编辑器。 以上是一个基本的实现思路。根据实际需求,你可能还需要调整样式和布局。 相关问题: 1. 如何实现wangEditor的内容实时保存? 2. wangEditor如何插入自定义元素? 3. 在Vue中如何实现富文本编辑器的撤销和重做功能? 4. 如何优化wangEditor在Vue项目中的性能?</think>下面是在 Vue 中实现固定 wangEditor 工具栏和自定义头部的完整解决方案: ### 实现思路 1. **固定工具栏**:使用 wangEditor 的 `excludeKeys` 配置分离工具栏和编辑区 2. **自定义头部**:创建独立组件实现标题栏功能 3. **布局结构**:使用 CSS Grid 实现侧边栏+主内容区的响应式布局 4. **滚动控制**:通过 `scrollIntoView` 实现平滑滚动 ### 完整实现代码 ```vue <template> <div class="editor-layout"> <!-- 自定义头部 --> <HeaderBar :title="pageTitle" @back="handleBack" @history="showHistory" /> <div class="main-container"> <!-- 侧边栏 --> <Sidebar :sections="sections" @navigate="scrollToSection"/> <!-- 编辑器区域 --> <div class="content-area"> <!-- 固定工具栏 --> <div ref="toolbar" class="fixed-toolbar"></div> <!-- 编辑区域 --> <div ref="editor" class="editor-content"></div> </div> </div> </div> </template> <script> import { onBeforeUnmount, onMounted, ref, shallowRef } from &#39;vue&#39; import &#39;@wangeditor/editor/dist/css/style.css&#39; import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; import HeaderBar from &#39;./HeaderBar.vue&#39; import Sidebar from &#39;./Sidebar.vue&#39; export default { components: { HeaderBar, Sidebar }, setup() { const toolbar = ref(null) const editor = ref(null) const editorInstance = shallowRef(null) const pageTitle = ref(&#39;文档编辑&#39;) const sections = ref([ { id: &#39;section1&#39;, title: &#39;第一章&#39; }, { id: &#39;section2&#39;, title: &#39;第二章&#39; } ]) // 初始化编辑器 onMounted(() => { // 创建编辑器实例 editorInstance.value = new Editor({ selector: editor.value, config: { placeholder: &#39;请输入内容...&#39;, scroll: false, // 禁用编辑器自滚动 excludeKeys: [&#39;fullScreen&#39;] // 排除不需要的工具栏项 } }) // 创建工具栏实例 new Toolbar({ editor: editorInstance.value, selector: toolbar.value, config: { excludeKeys: [&#39;insertImage&#39;, &#39;group-video&#39;] // 自定义工具栏项 } }) }) // 滚动到指定部分 const scrollToSection = (id) => { const element = document.getElementById(id) if (element) element.scrollIntoView({ behavior: &#39;smooth&#39; }) } // 返回按钮处理 const handleBack = () => { console.log(&#39;返回操作&#39;) } // 历史记录处理 const showHistory = () => { console.log(&#39;显示历史记录&#39;) } // 组件销毁时销毁编辑器 onBeforeUnmount(() => { if (editorInstance.value) editorInstance.value.destroy() }) return { toolbar, editor, pageTitle, sections, scrollToSection, handleBack, showHistory } } } </script> <style> .editor-layout { display: flex; flex-direction: column; height: 100vh; overflow: hidden; } .main-container { display: grid; grid-template-columns: 250px 1fr; flex: 1; overflow: hidden; } .content-area { display: flex; flex-direction: column; overflow: hidden; } .fixed-toolbar { position: sticky; top: 0; z-index: 100; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .editor-content { flex: 1; overflow-y: auto; padding: 20px; border: 1px solid #e8e8e8; } </style> ``` ### HeaderBar.vue 组件 ```vue <template> <header class="custom-header"> <button class="back-btn" @click="$emit(&#39;back&#39;)"> <i class="icon-back"></i> </button> <div class="title">{{ title }}</div> <div class="header-right"> <button class="history-btn" @click="$emit(&#39;history&#39;)"> <i class="icon-history"></i> </button> <div class="user-avatar"> <img :src="avatarUrl" alt="用户头像"> </div> </div> </header> </template> <script> export default { props: { title: String }, data() { return { avatarUrl: &#39;https://avatar.example.com/user.jpg&#39; } } } </script> <style> .custom-header { display: flex; align-items: center; padding: 0 20px; height: 60px; background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 1000; } .back-btn, .history-btn { width: 40px; height: 40px; border: none; background: none; cursor: pointer; } .title { flex: 1; text-align: center; font-size: 18px; font-weight: bold; } .header-right { display: flex; align-items: center; } .user-avatar img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; } </style> ``` ### 关键实现说明 1. **工具栏固定原理**: - 使用 `excludeKeys` 配置分离工具栏和编辑区 - 通过 CSS `position: sticky` 实现固定定位 - 禁用编辑器自滚动条(`scroll: false`) 2. **响应式布局**: ```css .main-container { display: grid; grid-template-columns: 250px 1fr; } ``` 使用 CSS Grid 实现侧边栏和主内容区的响应式布局[^1] 3. **滚动控制**: ```javascript const scrollToSection = (id) => { document.getElementById(id).scrollIntoView({ behavior: &#39;smooth&#39; }) } ``` 使用原生 DOM API 实现平滑滚动定位[^1] 4. **组件化结构**: - `HeaderBar`:处理头部导航逻辑 - `Sidebar`:管理文档章节导航 - 主组件:集成编辑器和布局控制 ### 注意事项 1. 使用 `shallowRef` 存储编辑器实例避免响应式代理问题 2. 组件销毁时务必调用 `editor.destroy()` 3. 工具栏固定高度需考虑头部高度避免重叠 4. 移动端需额外添加视口 meta 标签 ```html <meta name="viewport" content="width=device-width, initial-scale=1.0"> ``` ### 优化建议 1. **性能优化**: - 使用 `IntersectionObserver` 实现章节自动高亮[^1] - 对编辑器内容启用节流保存 - 使用 Vue 的 `keep-alive` 缓存组件状态 2. **功能扩展**: ```javascript // 添加自定义按钮 toolbarConfig.insertKeys = { index: 5, // 插入位置 keys: [&#39;customBtn&#39;] } ``` 3. **响应式处理**: ```css @media (max-width: 768px) { .main-container { grid-template-columns: 1fr; } .sidebar { display: none; /* 移动端隐藏侧边栏 */ } } ``` [^1]: vue-scrollactive-基于视口中的当前部分在菜单项中添加活动类,单击菜单项时也会滚动到该部分。 vue-intersect-将Vue组件添加到Vue组件或HTML元素的Vue组件。 vue-scrollmonitor-一个Vue插件,通过支持多种浏览器来监视视口内元素的可见性状态(使用provide / inject,因此兼容vue@2.2.x) vue-stroll -Vue.js 2.x的一个很棒的CSS3列表滚动效果组件。 navscroll-js-滚动时突出显示菜单项,并且单击菜单项时还会滚动到某个部分。用作vue组件,vue指令或与vanilla js一起使用。 vue-scrollwatch-一个轻巧的插件,可检测滚动事件,在元素进入视口时自定义回调,使用&#39;vue指令&#39;暴露&#39;scrollTo&#39;API滚动至特定元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值