- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
场景:
我正在开发一个 Vue 滚动组件,它包含动态数量的 HTML 部分,然后动态构建垂直页面导航,允许用户滚动或跳转到 onScroll 上的页面位置。
详情:
一个。 在我的示例中,我的滚动组件包含 3 个部分。所有部分 id 都以 "js-page-section-{{index}}"
开头
湾。 目标是获取部分节点列表(上图),然后根据在查询匹配选择器条件中找到的 n 个节点动态构建垂直页面 (nav) 导航。因此,三个部分将导致三个页面部分导航项。所有侧边导航都以 “js-side-nav-{{index}}>".
开头
C。 呈现侧面导航后,我需要查询所有导航节点以控制类、高度、显示、不透明度等。即 document.querySelectorAll('*[id^="js-side-nav"]');
编辑
根据一些研究,这里是我的问题的选项。我的问题再次是 3 阶段 DOM 状态管理,即第 1 步。读取所有等于 x 的节点,然后第 2 步。根据文档中的 n 个节点构建侧导航滚动,然后第 3 步。读取所有导航节点以与滚动同步文档节点数:
$emit() && $on
.在我看来,这很快就会变得一团糟,感觉就像一个糟糕的解决方案。我发现自己很快跳到 $root Vuex
.但这感觉有点矫枉过正sync
.有效,但实际上是用于父子属性状态管理,但这又需要 $emit() && $on
. Promise
.基于服务类。这似乎是正确的解决方案,但坦率地说,管理多个 promise 变得有点痛苦。 $nextTick()
.这似乎类似于 AngularJS $digest
.本质上它是一个 . setTimeout()
.类型方法只是暂停下一个摘要周期。也就是说,存在滴答声不同步所需时间的情况,因此我构建了一个节流方法。以下是有值(value)的代码更新。 watch: {
'page.sections': {
handler(nodeList, oldNodeList){
if (this.isNodeList(nodeList) && _.size(nodeList) && this.sideNavActive) {
return this.$nextTick(this.sideNavInit);
}
},
deep: true
},
},
<template>
<div v-scroll="handleScroll">
<nav class="nav__wrapper" id="navbar-example">
<ul class="nav">
<li role="presentation"
:id="sideNavPrefix + '-' + (index + 1)"
v-for="(item, key,index) in page.sections">
<a :href="'#' + getAttribute(item,'id')">
<p class="nav__counter" v-text="('0' + (index + 1))"></p>
<h3 class="nav__title" v-text="getAttribute(item,'data-title')"></h3>
<p class="nav__body" v-text="getAttribute(item,'data-body')"></p>
</a>
</li>
</ul>
</nav>
<slot></slot>
</div>
</template>
<script>
import ScrollPageService from '../services/ScrollPageService.js';
const _S = "section", _N = "sidenavs";
export default {
name: "ScrollSection",
props: {
nodeId: {
type: String,
required: true
},
sideNavActive: {
type: Boolean,
default: true,
required: false
},
sideNavPrefix: {
type: String,
default: "js-side-nav",
required: false
},
sideNavClass: {
type: String,
default: "active",
required: false
},
sectionClass: {
type: String,
default: "inview",
required: false
}
},
directives: {
scroll: {
inserted: function (el, binding, vnode) {
let f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
},
},
data: function () {
return {
scrollService: {},
page: {
sections: {},
sidenavs: {}
}
}
},
methods: {
getAttribute: function(element, key) {
return element.getAttribute(key);
},
updateViewPort: function() {
if (this.scrollService.isInCurrent(window.scrollY)) return;
[this.page.sections, this.page.sidenavs] = this.scrollService.updateNodeList(window.scrollY);
},
handleScroll: function(evt, el) {
if ( !(this.isScrollInstance()) ) {
return this.$nextTick(this.inViewportInit);
}
this.updateViewPort();
},
getNodeList: function(key) {
this.page[key] = this.scrollService.getNodeList(key);
},
isScrollInstance: function() {
return this.scrollService instanceof ScrollPageService;
},
sideNavInit: function() {
if (this.isScrollInstance() && this.scrollService.navInit(this.sideNavPrefix, this.sideNavClass)) this.getNodeList(_N);
},
inViewportInit: function() {
if (!(this.isScrollInstance()) && ((this.scrollService = new ScrollPageService(this.nodeId, this.sectionClass)) instanceof ScrollPageService)) this.getNodeList(_S);
},
isNodeList: function(nodes) {
return NodeList.prototype.isPrototypeOf(nodes);
},
},
watch: {
'page.sections': {
handler(nodeList, oldNodeList){
if (this.isNodeList(nodeList) && _.size(nodeList) && this.sideNavActive) {
return this.$nextTick(this.sideNavInit);
}
},
deep: true
},
},
mounted() {
return this.$nextTick(this.inViewportInit);
},
}
</script>
setTimeout()
功能。即使我使用 watch ,我仍然被迫使用超时。
<html>
<head></head>
<body>
<scroll-section>
<div id="js-page-section-1"
data-title="One"
data-body="One Body">
</div>
<div id="js-page-section-2"
data-title="Two"
data-body="Two Body">
</div>
<div id="js-page-section-3"
data-title="Three"
data-body="THree Body">
</div>
</scroll-section>
</body>
</html>
<template>
<div v-scroll="handleScroll">
<nav class="nav__wrapper" id="navbar-example">
<ul class="nav">
<li role="presentation"
:id="[idOfSideNav(key)]"
v-for="(item, key,index) in page.sections.items">
<a :href="getId(item)">
<p class="nav__counter">{{key}}</p>
<h3 class="nav__title" v-text="item.getAttribute('data-title')"></h3>
<p class="nav__body" v-text="item.getAttribute('data-body')"></p>
</a>
</li>
</ul>
</nav>
<slot></slot>
</div>
</template>
<script>
export default {
name: "ScrollSection",
directives: {
scroll: {
inserted: function (el, binding, vnode) {
let f = function(evt) {
_.forEach(vnode.context.page.sections.items, function (elem,k) {
if (window.scrollY >= elem.offsetTop && window.scrollY <= (elem.offsetTop + elem.offsetHeight)) {
if (!vnode.context.page.sections.items[k].classList.contains("in-viewport") ) {
vnode.context.page.sections.items[k].classList.add("in-viewport");
}
if (!vnode.context.page.sidenavs.items[k].classList.contains("active") ) {
vnode.context.page.sidenavs.items[k].classList.add("active");
}
} else {
if (elem.classList.contains("in-viewport") ) {
elem.classList.remove("in-viewport");
}
vnode.context.page.sidenavs.items[k].classList.remove("active");
}
});
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
},
},
},
data: function () {
return {
page: {
sections: {},
sidenavs: {}
}
}
},
methods: {
handleScroll: function(evt, el) {
// Remove for brevity
},
idOfSideNav: function(key) {
return "js-side-nav-" + (key+1);
},
classOfSideNav: function(key) {
if (key==="0") {return "active"}
},
elementsOfSideNav:function() {
this.page.sidenavs = document.querySelectorAll('*[id^="js-side-nav"]');
},
elementsOfSections:function() {
this.page.sections = document.querySelectorAll('*[id^="page-section"]');
},
},
watch: {
'page.sections': function (val) {
if (_.has(val,'items') && _.size(val.items)) {
var self = this;
setTimeout(function(){
self.elementsOfSideNavs();
}, 300);
}
}
},
mounted() {
this.elementsOfSections();
},
}
</script>
最佳答案
我希望我能帮助你解决我要在这里发布的内容。我的一个 friend 开发了一个我们在几个地方使用的功能,阅读你的问题让我想起了它。
"Is there a promise or observer in Vue or JS I can use to check to see when the DOM has finished rendering the nav elements so that I can then read them?"
/**
* Waits for object existence using a function to retrieve its value.
*
* @param { function() : T } getValueFunction
* @param { number } [maxTries=10] - Number of tries before the error catch.
* @param { number } [timeInterval=200] - Time interval between the requests in milis.
* @returns { Promise.<T> } Promise of the checked value.
*/
export function waitForExistence(getValueFunction, maxTries = 10, timeInterval = 200) {
return new Promise((resolve, reject) => {
let tries = 0
const interval = setInterval(() => {
tries += 1
const value = getValueFunction()
if (value) {
clearInterval(interval)
return resolve(value)
}
if (tries >= maxTries) {
clearInterval(interval)
return reject(new Error(`Could not find any value using ${tries} tentatives`))
}
}, timeInterval)
})
}
例子
function getPotatoElement () {
return window.document.querySelector('#potato-scroller')
}
function hasPotatoElement () {
return Boolean(getPotatoElement())
}
// when something load
window.document.addEventListener('load', async () => {
// we try sometimes to check if our element exists
const has = await waitForExistence(hasPotatoElement)
if (has) {
// and if it exists, we do this
doThingThatNeedPotato()
}
// or you could use a promise chain
waitForExistence(hasPotatoElement)
.then(returnFromWaitedFunction => { /* hasPotatoElement */
if (has) {
doThingThatNeedPotato(getPotatoElement())
}
})
})
关于javascript - VueJS/JS DOM Watch/Observer 多阶段渲染场景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54282942/
我试图将我的 VueJS 组件中的某些内容发送到位于包含该组件的 html 页面中的函数。我是否遗漏了什么,或者这是不可能的? 在我的组件中作为方法: insert: function(){
完全遵循 docs的语言说明,我正在尝试以德语格式显示日期。相反,我仍然看到它是英文的:“12 Apr 2020”。 也尝试使用西类牙语,仍然得到“2020 年 4 月 12 日”。 我错过了什么吗?
我想从 Chart 对象访问 getValue 方法,但我得到的函数未定义。 import Vue from 'vue'; import C
我正在使用 laravel-vuejs 应用程序。当 vuejs 渲染 css 时,它会在 html head 中附加一些样式标签,如下图所示。有什么办法可以隐藏这个标签吗?我认为可以通过添加一些插件
我正在为 VueJS 创建一个加载栏插件,我想使用该插件控制 VueJS 组件(插件的一部分)的数据。 所以,最后我想做以下事情: 在 main.js 中包含插件 import VueLoadingB
如何使用 VueJs 和 VueJS-Router 为 Pimcore 进行扩展? 到目前为止,前端的 vuejs 没有任何问题……但我无法让 VueJs-Router 运行。 有人有在 pimcor
也许你可以成为我一天的救世主。 我正在尝试为我的扩展实现 vue-components。 我不能包含自定义 Vue.js 组件。我关注了https://pagekit.com/docs/develop
我是 Laravel 和 VueJS 的新手,对于困惑的代码提前深表歉意。 我一直在尝试制作一个注册表单,并将 VueJS 集成到 laravel 中以使其更具动态性。现在我一直在尝试使用 {{ }}
我想使用函数作为数据属性。这似乎在“works”数据属性的情况下工作得很好。但是我需要函数中的 this 上下文,以便我可以计算存储在 this.shoppingCart (另一个属性)中的值。 这可
我正在尝试从另一个方法调用一个方法,为此我使用了它。但是我的控制台导致我出错。 如何在 Vuejs 中调用另一个方法中的方法? 代码 methods: { searchLocations:
我已经使用 webpack_loader 创建了 Django 和 VueJS 集成项目。Django 在本地主机 8000 上运行,而 VueJS 在 8080 端口上运行。但是端口 8000 在控
我正在学习如何通过 udemy 类(class)制作单页应用程序,同时尝试做一个大学项目。问题是,在我的 Controller 中,我将数据库查询作为 json“alunos”发送到前端。现在,在 V
我有一个带有一些 html 的#app 容器,我在#app 上创建了 Vue 实例,所有内容都被编译并转换为 Vuejs 组件。然后我在另一个 html 字符串中使用 ajax,我需要以某种方式将其编
我有一个 symfony 2.8 应用程序,我最近集成了 VueJs 2 作为我的前端框架,因为它提供了很大的灵 active 。我的应用程序不是单页的,我使用 symfony Controller
好吧,我遇到了一个问题,虽然是一个奇怪的问题,但我到处都找不到答案。 我们被指派用 Vue.js 创建一个购物车,我已经完成了我自己开始了这个项目,想看看我能用 vuejs 做什么。问题出现在页面加载
逻辑 我有带有输入作为标签的复选框,其值来自数据库,因此文本(值)已经存在。 (完成) 我想列一份检查项目 list (完成) 我想如果我改变了一个项目的值得到改变的值,但它仍然给我数据库的值(需要帮
我正在尝试在页面上显示公告列表(从 API 检索)。我正在使用 Vuex 商店,我有一个名为 announcements 的状态。我还希望每次用户刷新/进入页面时更新此列表。所以我使用了生命周期钩子(
使用单文件模板,我希望有一个按钮,如果数组为空,则显示“单击此处”,如果数组已填充,则显示值。 ajax 工作正常并且对象正在更新,但按钮不会重新呈现。我在这里做错了什么? Mobil
在 VueJS 中,有没有办法在模板或脚本中将字符串插入字符串?例如,我希望以下内容显示 1 + 1 = 2 而不是 1 + 1 = {{ 1 + 1 }}。 {{ myVar }}
我在我的项目中使用 VueJS 2,我意识到我的构建部署很糟糕。 这是我在 github 上部署我的 VueJS 构建的脚本: #!/usr/bin/env sh # abort on errors
我是一名优秀的程序员,十分优秀!