Я пытаюсь заставить эту Навигацию с плавной прокруткой работать в Svelte. Но, тем не менее, этот объект ошибки TypeScript, возможно, имеет значение «null».ts(2531).
Я понял, что эта ошибка связана с тем, что TypeScript считает, что этот элемент может иметь значение null.
Поэтому я должен объявить, что это за элемент, с помощью оператора if или использовать оператор восклицательного знака ! (например, это не нуль).
Я пробовал множество возможностей для обоих решений, но все еще безуспешно.
REPL полного кода в svelte, где видно, что IntersectionObserver не работает.
<script>
import { onMount } from 'svelte';
let id;
onMount(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
id = entry.target.getAttribute('id');
if (entry.intersectionRatio > 0) {
document.querySelector(`nav li a[href = "#${id}"]`) //error
.parentElement //error
.classList
.add('active');
} else {
document.querySelector(`nav li a[href = "#${id}"]`) //error
.parentElement //error
.classList
.remove('active');
};
});
document.querySelectorAll('section[id]').forEach((section) => {
observer.observe(section);
});
});
});
</script>
Оригинальный код от Bram. Спасибо, что поделился.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Рекомендовал бы либо не позволять TypeScript проверять код JS, либо использовать TypeScript.
Первый должен быть настроен с помощью tsconfig.json опции checkJs.
Для последнего вы должны использовать svelte-preprocess (см. документацию) и объявить язык скрипта:
<script lang = "ts"> ...
В противном случае вы не сможете использовать специфичный для TS синтаксис, такой как !, или утверждения типа.
Чтобы устранить возможные ошибки null/undefined, вы всегда можете использовать операторы if, но вам нужно извлечь переменную, содержащую соответствующее значение:
const element = document.querySelector('...');
if (element) {
// element will be defined here
}
Спасибо за Ваш ответ. Я определил <script lang = "ts"> в своем коде, но забыл написать его в рассматриваемом коде. Когда я устанавливал SvelteKit, я принял вариант с TypeScript, поэтому я подумал, что TS поддерживается. Я пытался отключить checkJS и все равно не работает, потом попробовал поставить strictNullChecks:false но все равно не работает. Хотя я сделал это в jsconfig.json, я не уверен, что это то же самое, но у Svelte есть этот файл. Я попытаюсь извлечь переменную, содержащую значение ... также я не знал о svelte-preprocess, поэтому мне нужно проверить документацию. Спасибо, Х.Б.
Я действительно не думаю, что рекомендация пользователю отключить TS принесет им пользу, особенно в этом случае, поскольку это может привести к реальным ошибкам в их приложении.
@MarcosSandrini: я говорил только о функции проверки JS, которая не так хороша, поскольку вы не можете использовать синтаксис TS для исправления ошибок, требующих выразительности TS.
@Х.Б. хорошо, справедливое замечание. Но это может быть неправильно истолковано, например, если это первое, что вы говорите в своем ответе, некоторые люди, менее терпеливые, чтобы прочитать его, могут воспринять это как главный совет.
Когда вы пишете:
document.querySelector(`nav li a[href = "#${id}"]`)
Результат этого выражения может быть нулевым, например, он ничего не может найти. TS очень мудро говорит, что вы должны помнить об этом, иначе ваше приложение может дать сбой, и, возможно, преобразовать это в какое-то выражение, в котором учитывается нулевой регистр. Одно предложение:
const element = document.querySelector(`nav li a[href = "#${id}"]`)
if (element && element.parentElement) {
element.parentElement.classList.add('active');
}
Таким образом, вы принимаете во внимание случай null. Кроме того, я думаю, что строка document.querySelectorAll('section[id]')... должна быть за пределами блока new IntersectionObserver ..., как отметил @Desjardins.
Обновлено: добавлено одно условие. Спасибо @Desjardins.
Спасибо, Маркос, но до сих пор не могу понять окончательную структуру. Я определил строку const element ... , а затем изменил оператор if на этот if (entry.intersectionRatio > 0 && element) {element.parentElement.classList.add('active'); } else if (element) {element.parentElement.classList.remove('active');};, но безуспешно. Я что-то пропустил?
Node.parentElement также может быть нулевым, поэтому вам также необходимо проверить его на нуль, чтобы избежать ошибки TypeScript. Но имейте в виду, что это просто ошибка TypeScript — проблема с IntersectionObserver все еще существует.
Добавил туда одно условие, чтобы учесть очень полезный комментарий выше.
ДА! Я сделал это.
Функциональная версия TOC (Table of Content) для Svelte с настраиваемым классом, который показывает и отслеживает активный элемент в списке TOC в соответствии с содержимым (заголовком, текстом) в окне просмотра.
<script lang = "ts">
import { onMount } from 'svelte';
let id
let element
onMount(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
id = entry.target.getAttribute('id');
if (entry.intersectionRatio > 0) {
element = document.querySelector(`nav li a[href = "#${id}"]`);
if (element && element.parentElement ) {
element.parentElement.classList.add('active');
}
} else {
element = document.querySelector(`nav li a[href = "#${id}"]`)
if (element && element.parentElement ) {
element.parentElement.classList.remove('active');
}
};
});
});
// Track all sections that have an `id` applied
document.querySelectorAll('section[id]').forEach((section) => {
observer.observe(section);
});
});
</script>
Это скорректированная версия исходного кода для Svelte. Создатель Брэм загляните в его блог.
Не имеет отношения к вашей проблеме
object is possibly 'null', но я думаю, что вы все еще находитесь внутри обратного вызова конструктораIntersectionObserver, когда выполняетеdocument.querySelectorAll('section[id]'), поэтому наблюдатель никогда не сможет ничего наблюдать, и его обратный вызов никогда не будет вызван.