require
работает на этапе компиляции. Т.е. во время исполнения он уже должен был собрать все вызовы require
и положить их в .js
файл. require
не может быть динамичным, потому что на этапе исполнения его тупо уже нет - он заменён на то, что он возвращает.img
уже сейчас лежат все нужные изображения.require
тебе тут не нужен(и не поможет), просто динамически подставляй пути к ним как в твоём первом варианте.__webpack_public_path__
:root: __webpack_public_path__,
<img :src="root + 'img/' + message.filename" :alt="message.filename"/>
const result = await modal({
title: ...,
type: 'confirm',
acceptText: 'Подтвердить',
...
})
showPopup() {
this.isDialogShown = true;
this.pending = new Promise((resolve) => {
this.discardChanges = () => resolve(false);
this.saveChanges = () => resolve(true);
});
},
async changeTab() {
...
return await this.pending;
}
changeTab() {
return new Promise((resolve) => {
this.discardChanges = () => resolve(false);
this.saveChanges = () => resolve(true);
});
}
index
- и есть в данном случае ключ. Т.е. проверять нужно просто index === 'dateTime'
.v-for="(filter, key, index) in filters"
. Однако в твоём случае он не нужен, т.к. лучше привязывать key
именно к ключу.prettier
- это одно, eslint
- это другое, если у тебя prettier
подключается через eslint
, то настройки для него указываются скопом, условно так:rules: {
'prettier/prettier': ['warn', {
semi: false,
...
singleQuote: true,
vueIndentScriptAndStyle: true,
arrowParens: 'avoid',
trailingComma: 'none',
quoteProps: 'consistent',
}],
const options = computed(() => {
if (props.secondType)
return props.secondTypeItems.map(({ id, value}) => ({
label: value,
value: id
}));
if (props.thirdType)
return props.thirdTypeEvents.map(({ desc, name }) => ({
label: name,
value: desc
}));
// ...
return [];
});
<el-select
v-model="modelText"
placeholder="Выберите предмет"
@change="changeVal"
>
<el-option
v-for="{ label, value} in options"
:key="value"
:label="label"
:value="value"
>
{{ label }}
</el-option>
</el-select>
axios.post('http://localhost:5000/api/create-post', () => {
body: data
})
Во-первых: axios
принимает параметром объект, а не функцию возвращающую объект.axios.post
вообще сразу принимает body: axios.post('http://localhost:5000/api/create-post', data)
() => {
body: data
}
на самом деле расшифровывается так: () => { // начало блока кода
// метка body указывающий на висящую в воздухе переменную data
body: data
// никакого возврата из функции
} // конец блока кода
чтобы оно воспринималось как объект, можно, например, заключать в скобки: () => ({
body: data
})
// версия с рантайм компилятором шаблонов
import { createApp } from 'vue/dist/vue.esm-bundler.js';
function renderVueComponent(template, data) {
const div = document.createElement('div');
createApp({
template,
data: () => data
}).mount(div);
return div.innerHTML;
}
route
?route
у тебя - это текущий роут vue-рутера, тогда ошибка у тебя скорее всего выглядит как-то так:TS7053: Element implicitly has an 'any' type because expression of type 'RouteRecordName' can't be used to index type '{ first: string; second: string; }'. No index signature with a parameter of type 'string' was found on type '{ first: string; second: string; }'.
pages
есть ключи типа 'first' | 'second' | ...
, но нет index signature типа string
, т.е. не указано, что ключом может быть любая строка, а не только конкретные'first' | 'second' | ...
. route.name
же после проверки на пустоту имеет тип string | symbol
. Ты не можешь у объекта с чётко ограниченным набором ключей брать значение по произвольному строковому/символьному.pages
позволяющий рандомные ключи, например const pages: Record<PropertyKey, string> = {
first: 'Первая',
second: 'Вторая',
...
}
... = pages[route.name as keyof typeof pages]
name
в route
всегда будет одним из ключей pages
. Уверены же?..export enum ERoutes {
FIRST = 'first',
SECOND = 'second'
}
const routes = [
{
name: ERoutes.FIRST,
...
},
{
name: ERoutes.SECOND,
...
},
...
]
const pages: Record<ERoutes, string> = {
[ERoutes.FIRST]: 'Первая',
[ERoutes.SECOND]: 'Вторая',
...
}
... = pages[route.name as ERoutes]
const routes = [
{
name: 'first',
...
},
{
name: 'second',
...
},
...
] as const satisfies ReadonlyArray<ReadonlyRouteRecordRaw>;
type ReadonlyRouteRecordRaw = Omit<RouteRecordRaw, 'children'> & {
children?: ReadonlyArray<ReadonlyRouteRecordRaw>;
};
type ExtractNames<Route> = Route extends { name: infer Name } ? Name : never;
type FlattenChildren<Route> = Route extends { children: ReadonlyArray<infer Children> }
? FlattenChildren<Children> | Route
: Route;
// с помощью магии ts вытаскиваем в тип RouteNames все заданные у нас имена маршрутов
export type RouteNames = ExtractNames<FlattenChildren<typeof routes[number]>>;
// с помощью магии же прокидывем их прямо в декларацию vue-router
declare module 'vue-router' {
export interface RouteLocationNormalizedLoaded {
name: RouteNames | null | undefined;
}
}
satisfies
- новая фича ts 4.9, в предыдущих версиях того же можно добиться сделав обёртку вида:const narrowRoutesTypeWrapper = <T extends ReadonlyArray<ReadonlyRouteRecordRaw>>(routes: T) => routes;
const routes = narrowRoutesTypeWrapper([ ... ] as const);
const pages: Record<RouteNames, string> = {
first: 'Первая',
second: 'Вторая',
...
}
о какой рендер функции идет речь?
<template>
.(под капотом <template>
компилируется в render-функцию)setup
, можно класть в свойство render
.script setup,
можно сделать так:<template>
<div>
<render/>
</div>
</template>
<script setup lang="ts">
import { h, useSlots } from 'vue'
const slots = useSlots();
const render = () => {
return h('div', slots.default());
};
</script>
export default defineComponent({
name: 'CounterButton',
props: {
count: {
type: Number,
default: 0
}
},
template: `<button type="button" @click="counter++">{{counter}}</button>`,
emits: ['update:count'],
setup(props, context) {
const innerCounter = ref(props.count);
watch(() => props.count, (value) => innerCounter.value = value);
return {
counter: computed({
get: () => innerCounter.value,
set: (value) => context.emit('update:count', innerCounter.value = value)
})
}
}
})