Я хочу, чтобы окно загрузки изображений открывалось и закрывалось. В моем коде функция открытия работает, но по какой-то причине не работает функция закрытия. Кроме того, когда я использую console.info
в функциях, отвечающих за открытие и закрытие, console.info
в функции закрытия выполняется дважды. Я также пробовал использовать другой подход variable = !variable
, но при этом подходе возникает проблема: при нажатии кнопки ввода файла страница перерисовывается, что сбрасывает переменную состояния в значение false, в результате чего окно снова закрывается. Кто-нибудь знает, как это исправить?
<script>
let article = {}
let base64Image
let articleViewer
let imageUploadBox
function showImageUpload(){
if (imageUploadBox.classList.contains("hidden")){
imageUploadBox.classList.remove("hidden")
console.info(imageUploadBox.classList)
}
}
function closeImageUpload(){
if (!imageUploadBox.classList.contains("hidden")){
imageUploadBox.classList.add("hidden")
console.info(imageUploadBox.classList)
}
}
function processImage(e){
const image = e.target.files[0]
const imageReader = new FileReader()
imageReader.onload = (e) => {
base64Image = e.target.result
}
imageReader.readAsDataURL(image)
}
function insertImage(image){
let selection = window.getSelection()
let range = selection.getRangeAt(0)
if (articleViewer.contains(range.commonAncestorContainer)){
let imgTag = document.createElement("img")
imgTag.src = image
imgTag.className = "w-[50%] m-auto rounded-lg"
range.deleteContents()
range.insertNode(imgTag)
range.setStartAfter(imgTag)
range.collapse(true)
selection.removeAllRanges()
selection.addRange(range)
base64Image = ""
}
else {
alert("Images can only be inserted in the article content")
}
}
function updateArticle(){}
</script>
<div class = "flex flex-col gap-4 p-8 h-screen">
<input type = "text" class = "bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:value = {article["title"]} />
<div class = "relative">
<button on:click = {() => showImageUpload()} >
<svg viewBox = "0 0 48 48" xmlns = "http://www.w3.org/2000/svg" height = "40px" width = "40px"><path fill = "white" d = "M13.3 34.15h21.45q.5 0 .7-.4.2-.4-.1-.8l-5.85-7.8q-.25-.3-.6-.3t-.6.3l-6 7.75-4.05-5.55q-.25-.3-.6-.3t-.6.3l-4.3 5.6q-.25.4-.075.8t.625.4ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/></svg>
<!--{#if imageUploadBox}-->
<div class = "hidden bg-emerald-500 p-8 rounded-lg flex justify-center items-center flex-col gap-8 absolute top-[110%] relative" bind:this = {imageUploadBox}>
<input type = "file" accept = "images/*" on:change = {processImage} class = "rounded-lg text-emerald-100 text-xs font-semibold bg-emerald-950 p-4" />
{#if base64Image}
<img src = {base64Image} class = "rounded-lg w-[50%]" />
<button on:click = {insertImage(base64Image)} class = "bg-emerald-950 text-emerald-100 p-4 text-xs font-semibold rounded-lg" >Add</button>
{/if}
<button on:click = {closeImageUpload} class = "p-4 rounded-full absolute bottom-[100%] right-[100%] bg-emerald-950" >
<svg viewBox = "0 0 48 48" xmlns = "http://www.w3.org/2000/svg" height = "1.5em" width = "1.5em"><path fill = "white" d = "M24 26.1 13.5 36.6q-.45.45-1.05.45-.6 0-1.05-.45-.45-.45-.45-1.05 0-.6.45-1.05L21.9 24 11.4 13.5q-.45-.45-.45-1.05 0-.6.45-1.05.45-.45 1.05-.45.6 0 1.05.45L24 21.9l10.5-10.5q.45-.45 1.05-.45.6 0 1.05.45.45.45.45 1.05 0 .6-.45 1.05L26.1 24l10.5 10.5q.45.45.45 1.05 0 .6-.45 1.05-.45.45-1.05.45-.6 0-1.05-.45Z"/></svg>
</button>
</div>
<!--{/if}-->
</button>
</div>
<div id = "articleViewer" class = "bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:innerHTML = {article["content"]} contenteditable = "true" bind:this = {articleViewer}>hello</div>
</div>
<style>
input:active {
border: 0;
outline: 0;
}
.hidden {
display: none;
}
</style>
Другой подход, вызывающий повторную отрисовку: повторная отрисовка происходит, когда я нажимаю <input type = "file" />
:
<script>
let article = {}
let base64Image
let articleViewer
let imageUploadBox = false
function showImageUpload(){
imageUploadBox = !imageUploadBox
}
function closeImageUpload(){
imageUploadBox = !imageUploadBox
}
function processImage(e){
const image = e.target.files[0]
const imageReader = new FileReader()
imageReader.onload = (e) => {
base64Image = e.target.result
}
imageReader.readAsDataURL(image)
}
function insertImage(image){
let selection = window.getSelection()
let range = selection.getRangeAt(0)
if (articleViewer.contains(range.commonAncestorContainer)){
let imgTag = document.createElement("img")
imgTag.src = image
imgTag.className = "w-[50%] m-auto rounded-lg"
range.deleteContents()
range.insertNode(imgTag)
range.setStartAfter(imgTag)
range.collapse(true)
selection.removeAllRanges()
selection.addRange(range)
base64Image = ""
}
else {
alert("Images can only be inserted in the article content")
}
}
function updateArticle(){}
</script>
<div class = "flex flex-col gap-4 p-8 h-screen">
<input type = "text" class = "bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:value = {article["title"]} />
<div class = "relative">
<button type = "button" on:click = {() => showImageUpload()} >
<svg viewBox = "0 0 48 48" xmlns = "http://www.w3.org/2000/svg" height = "40px" width = "40px"><path fill = "white" d = "M13.3 34.15h21.45q.5 0 .7-.4.2-.4-.1-.8l-5.85-7.8q-.25-.3-.6-.3t-.6.3l-6 7.75-4.05-5.55q-.25-.3-.6-.3t-.6.3l-4.3 5.6q-.25.4-.075.8t.625.4ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/></svg>
{#if imageUploadBox}
<div class = "bg-emerald-500 p-8 rounded-lg flex justify-center items-center flex-col gap-8 absolute top-[110%] relative">
<input type = "file" accept = "images/*" on:change = {processImage} class = "rounded-lg text-emerald-100 text-xs font-semibold bg-emerald-950 p-4" />
{#if base64Image}
<img src = {base64Image} class = "rounded-lg w-[50%]" />
<button type = "button" on:click = {() => insertImage(base64Image)} class = "bg-emerald-950 text-emerald-100 p-4 text-xs font-semibold rounded-lg" >Add</button>
{/if}
<button type = "button" on:click = {closeImageUpload} class = "p-4 rounded-full absolute bottom-[100%] right-[100%] bg-emerald-950" >
<svg viewBox = "0 0 48 48" xmlns = "http://www.w3.org/2000/svg" height = "1.5em" width = "1.5em"><path fill = "white" d = "M24 26.1 13.5 36.6q-.45.45-1.05.45-.6 0-1.05-.45-.45-.45-.45-1.05 0-.6.45-1.05L21.9 24 11.4 13.5q-.45-.45-.45-1.05 0-.6.45-1.05.45-.45 1.05-.45.6 0 1.05.45L24 21.9l10.5-10.5q.45-.45 1.05-.45.6 0 1.05.45.45.45.45 1.05 0 .6-.45 1.05L26.1 24l10.5 10.5q.45.45.45 1.05 0 .6-.45 1.05-.45.45-1.05.45-.6 0-1.05-.45Z"/></svg>
</button>
</div>
{/if}
</button>
</div>
<div id = "articleViewer" class = "bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:innerHTML = {article["content"]} contenteditable = "true" bind:this = {articleViewer}>hello</div>
</div>
<style>
input:active {
border: 0;
outline: 0;
}
.hidden {
display: none;
}
</style>
🤔 А знаете ли вы, что...
JavaScript - это скриптовый язык программирования, разработанный Netscape Communications Corporation.
Если я не ошибаюсь в вашем вопросе, вы можете инициализировать локальную переменную, чтобы отслеживать состояние открытия/закрытия. Избавьтесь от closeImageUpload
и showImageUpload
и используйте привязку классов Svelte следующим образом:
<div
class:hidden = {!isOpen}
bind:this = {imageUploadBox}
class = "bg-emerald-500 p-8 rounded-lg flex justify-center items-center flex-col gap-8 absolute top-[110%] relative">
...
</div>
Наконец, я не проверял это, но основная причина вашей проблемы, вероятно, связана с наличием двух вложенных кнопок, которые могут мешать. В Svelte 5 этот синтаксис изменился, но в Svelte 3 и 4 вам следует использовать
stopPropagation
модификатор события вот так:
<button on:click|stopPropagation = {() => (isOpen = false)} class = "p-4 rounded-full absolute bottom-[100%] right-[100%] bg-emerald-950" >
<svg>...</svg>
</button>
а для внешней кнопки просто установите isOpen
на true
.
<button on:click = {() => (isOpen = true)}>