Cannot use import statement outside a module
<script src="script.js" type="module"></script>
При выполнении в консоли команды node index.js я получаю ошибку:
To load an ES module, set"type": "module"
in thepackage.json
or use the .mjs extension
useModal()
создаются свои личные isShowModal
, openModal
, closeModal
переменные.modal-state.js
нужно оформить в виде класса, и передавать экземпляр* этого класса компоненту в виде пропса.modal-state.js
по сути синглтон.Как установить и настроить Vue.js?
npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
npm run dev
yarn
(npm install --global yarn
) вместо npm
это будет заметно быстрее:yarn create vite my-vue-app --template vue
cd my-vue-app
yarn install
yarn run dev
server.open
в vite.config.js
import {defineConfig} from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [
vue(),
],
server: {
open: "/"
}
});
HelloWorld.vue
, в случае VSCode следует установить соответствующий плагин для код ассистанса, подсветки синтаксиса Vue 3. response.ok
не срабатывает, т.к. response.status.toString().startsWith("2") === false
{mode: "no-cors"}
Это условие скопировано с сайта javascript.ru.
let response = await fetch(url);
if (response.ok) { // если HTTP-статус в диапазоне 200-299
// получаем тело ответа (см. про этот метод ниже)
let json = await response.json();
} else {
alert("Ошибка HTTP: " + response.status);
}
Мне непонятно, почему этот код выводит 2
2 < 2 === false
, и второй цикл просто пропускается.2
и выводится.function isPrime(number) {
// ...
return true; // false
}
const max = 10;
for (let i = 0; i <= max; i++) {
if (isPrime(i)) {
alert(i);
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
for (let i = 0; i < 10; i++) {
for (let j = 5; j > 0; j--) {
console.log(i, j);
await sleep(500);
}
await sleep(2000);
}
fetch().then().then()
, собрав их в массиве.const promises /* !!! */ = json.dialogs.map((v) => {
let dialogId = v.dialogId;
return /* !!! */ fetch(`${this.WebApiHost}/api/qwe/dialogs/${dialogId}/${this.My_Token}`)
// ....
});
await Promise.allSettled(promises);
async
/await
и не использовать асинхронные функции в map
/forEach
:try {
const resp = await fetch("");
const json = await resp.json();
if (!json || json.error === true) {
console.log("error");
}
async function handleDialog(dialog) {
try {
const resp = await fetch("");
const json = await resp.json();
// ...
} catch (e) {
// ...
}
}
const concurrently = false;
if (concurrently) {
// [Way 1] Run one by one ---------
for (const dialog of []) {
await handleDialog(dialog);
}
} else {
// [Way 2] Run all concurrently ---
const promises = [];
for (const dialog of []) {
promises.push(handleDialog(dialog));
}
await Promise.allSettled(promises);
}
// The best way: concurrently with limitation
// @see https://qna.habr.com/q/1105356#answer_2098042
// ...
} catch (e) {
// ...
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function download(blob, name, url) {
const anchor = document.createElement("a");
anchor.setAttribute("download", name || "");
const blobUrl = URL.createObjectURL(blob);
anchor.href = blobUrl + (url ? ("#" + url) : "");
anchor.click();
setTimeout(() => URL.revokeObjectURL(blobUrl), 5000);
}
url
(третий параметр) к blobUrl
, может потом пригодиться — посмотреть, откуда (по какой именно ссылке) файл был скачен.blob:https://imgur.com/11fb6df9-e45b-4acf-b3eb-60d5d4656747#https://i.imgur.com/X92aA5Y.jpeg
for (const url of urls) {
const resp = await fetch(url);
const blob = await resp.blob();
const name = new URL(url).pathname.match(/[^\/]*$/)[0];
download(blob, name, url);
await sleep(200);
}
arrayBuffer
у это объекта. event.target.files[0]
— это объект класса File
, который в свою очередь наследуется от класса Blob
. [somebody=John Doe]
[somebody="John Doe"]
SHA512
An implementation of Secure Hashing Algorithm 2 (SHA-2) hashing with a 512-bit digest.
SHA512Digest
The output of a Secure Hashing Algorithm 2 (SHA-2) hash with a 512-bit digest.
import {ref, readonly} from "vue";
const todo = ref(null);
const todoId = ref(1);
export async function fetchTodo() {
const resp = await fetch("https://jsonplaceholder.typicode.com/todos/" + todoId.value++);
todo.value = await resp.json();
};
// Using of `readonly` is optional, I use it just in case.
// You can just export `todoId`, `todo` (above) as is.
const _todoId = readonly(todoId);
const _todo = readonly(todo);
export {
_todoId as todoId,
_todo as todo
};
<template>
<Button/>
<div v-if="todo">
{{todo}}
</div>
</template>
<script setup>
import Button from "./Button.vue";
import {todo} from "./core.js";
</script>
<template>
<button @click="fetchTodo">fetchTodo({{todoId}})</button>
</template>
<script setup>
import {fetchTodo, todoId} from "./core.js";
</script>
class Semaphore {
constructor(max = 1) {
if (max < 1) { max = 1; }
this.max = max;
this.count = 0;
this.queue = [];
}
acquire() {
let promise;
if (this.count < this.max) {
promise = Promise.resolve();
} else {
promise = new Promise(resolve => {
this.queue.push(resolve);
});
}
this.count++;
return promise;
}
release() {
if (this.queue.length > 0) {
const resolve = this.queue.shift();
resolve();
}
this.count--;
}
}
const semaphore = new Semaphore(10);
for (const url of urls) {
await semaphore.acquire();
void downloadUrlSynchronized(url, semaphore);
}
async function downloadUrlSynchronized(url, semaphore) {
const resp = await fetch(url);
const blob = await resp.blob();
semaphore.release();
// const name = new URL(url).pathname.slice(1);
// downloadBlob(blob, name, url);
}
fetch
) будет не больше 10 в один момент, что собственно и требовалось.3
:<script setup>
import {ref, computed, watchEffect} from "vue";
const phones = ref([
{ title: "iPhone 12", company: "Apple", price: 65000 },
{ title: "Galaxy S20", company: "Samsung", price: 63000 },
{ title: "Galaxy A10", company: "Samsung", price: 38000 },
{ title: "iPhone 10", company: "Apple", price: 45000 },
{ title: "Xiaomi Redmi 8", company: "Xiaomi", price: 42000 },
]);
const companySearch = ref("");
const filteredList = computed(() => {
if (!companySearch.value) {
return phones.value;
}
const search = companySearch.value.trim().toLowerCase();
return phones.value.filter(elem => elem.company.toLowerCase().startsWith(search)); // .includes(search)
});
const sortParam = ref("");
const sortByTitle = (p1, p2) => p1.title.localeCompare(p2.title, undefined, {sensitivity: "base"});
const sortByCompany = (p1, p2) => p1.company.localeCompare(p2.company, undefined, {sensitivity: "base"});
const sortByPrice = (p1, p2) => p1.price - p2.price;
const sortedList = ref([]);
watchEffect(() => {
const array = filteredList.value; //const array = [...filteredList.value];
if (sortParam.value === "title") {
sortedList.value = array.sort(sortByTitle);
} else if (sortParam.value === "company") {
sortedList.value = array.sort(sortByCompany);
} else if (sortParam.value === "price") {
sortedList.value = array.sort(sortByPrice);
} else {
sortedList.value = array;
}
});
</script>
<script setup>
import {ref, computed} from "vue";
const phones = ref([
{ title: "iPhone 12", company: "Apple", price: 65000 },
{ title: "Galaxy S20", company: "Samsung", price: 63000 },
{ title: "Galaxy A10", company: "Samsung", price: 38000 },
{ title: "iPhone 10", company: "Apple", price: 45000 },
{ title: "Xiaomi Redmi 8", company: "Xiaomi", price: 42000 },
]);
const companySearch = ref("");
const filteredList = computed(() => {
if (!companySearch.value) {
return phones.value;
}
const search = companySearch.value.trim().toLowerCase();
return phones.value.filter(elem => elem.company.toLowerCase().startsWith(search)); // .includes(search)
});
/** @type {import("vue").Ref<("title"|"company"|"price")>} */
const orderBy = ref("title");
const orders = ref({ // if `true` — an order is reversed
title: false,
company: false,
price: false,
});
const isOrderReversed = computed(() => orders.value[orderBy.value]);
function toggleOrder() {
orders.value[orderBy.value] = !orders.value[orderBy.value];
}
/** @param {"title"|"company"|"price"} value */
function setOrderBy(value) {
if (orderBy.value === value) {
toggleOrder();
}
orderBy.value = value;
};
const {compare} = new Intl.Collator(undefined, {sensitivity: "base"});
function comparator(pre, cur) {
const k = isOrderReversed.value ? -1 : 1;
if (orderBy.value === "title") {
return compare(pre.title, cur.title) * k;
} else if (orderBy.value === "company") {
return compare(pre.company, cur.company) * k;
} else if (orderBy.value === "price") {
return (pre.price - cur.price) * k;
}
return 0;
}
const sortedList = computed(() => {
return filteredList.value.sort(comparator);
});
</script>