Динамический импорт изображений из каталога с помощью веб-пакета
Итак, вот мой текущий рабочий процесс для импорта изображений и значков в веб-пакете через ES6:
import cat from './images/cat1.jpg'
import cat2 from './images/cat2.svg'
import doggy from './images/doggy.png'
import turtle from './images/turtle.png'
<img src={doggy} />
Это быстро становится грязным. Вот что я хочу:
import * from './images'
<img src={doggy} />
<img src={turtle} />
Я чувствую, что должен быть какой-то способ динамически импортировать все файлы из определенного каталога с расширением их имени без расширения, а затем использовать эти файлы по мере необходимости.
Кто-нибудь видел, что это сделано, или есть мысли о том, как это сделать?
ОБНОВИТЬ:
Используя выбранный ответ, я смог сделать это:
function importAll(r) {
let images = {};
r.keys().map((item, index) => { images[item.replace('./', '')] = r(item); });
return images;
}
const images = importAll(require.context('./images', false, /\.(png|jpe?g|svg)$/));
<img src={images['doggy.png']} />
6 ответов
Я чувствую, что должен быть какой-то способ динамически импортировать все файлы из определенного каталога с расширением их имени без расширения, а затем использовать эти файлы по мере необходимости.
Не в ES6. Весь смысл import
а также export
является то, что зависимости могут быть определены статически, т.е. без выполнения кода.
Но так как вы используете веб-пакет, взгляните на require.context
, Вы должны быть в состоянии сделать следующее:
function importAll(r) {
return r.keys().map(r);
}
const images = importAll(require.context('./', false, /\.(png|jpe?g|svg)$/));
Это просто. Ты можешь использовать require
(статический метод, импорт предназначен только для динамических файлов) внутри render
, Как пример ниже:
render() {
const {
someProp,
} = this.props
const graphImage = require('./graph-' + anyVariable + '.png')
const tableImage = require('./table-' + anyVariable2 + '.png')
return (
<img src={graphImage}/>
)
}
Функциональный подход к решению этой проблемы:
const importAll = require =>
require.keys().reduce((acc, next) => {
acc[next.replace("./", "")] = require(next);
return acc;
}, {});
const images = importAll(
require.context("./image", false, /\.(png|jpe?g|svg)$/)
);
У меня есть каталог с флагами стран png с именами au.png, nl.png и т. Д. Итак, у меня есть:
-svg-country-flags
--png100px
---au.png
---au.png
--index.js
--CountryFlagByCode.js
index.js
const context = require.context('./png100px', true, /.png$/);
const obj = {};
context.keys().forEach((key) => {
const countryCode = key.split('./').pop() // remove the first 2 characters
.substring(0, key.length - 6); // remove the file extension
obj[countryCode] = context(key);
});
export default obj;
Я читаю такой файл:
CountryFlagByCode.js
import React from 'react';
import countryFlags from './index';
const CountryFlagByCode = (countryCode) => {
return (
<div>
<img src={countryFlags[countryCode.toLowerCase()]} alt="country_flag" />
</div>
);
};
export default CountryFlagByCode;
Вот функциональный компонент, который я сделал в Reactjs, чтобы просто показать все изображения внутри
media
папка в моем проекте (на том же уровне, что и компонент), используя документы webpack и некоторые ответы здесь.
import React from 'react';
const cache = {};
function importAll(r) {
r.keys().forEach((key) => (cache[key] = r(key)));
}
// Note from the docs -> Warning: The arguments passed to require.context must be literals!
importAll(require.context("./media", false, /\.(png|jpe?g|svg)$/));
const images = Object.entries(cache).map(module => module[1].default);
const MediaPage = () => {
return (
<>
<p>Media Page..</p>
{images.map(image => (
<img style={{width: 100}} src={image} />
))}
</>
);
}
export default MediaPage;
Благодаря тому, как я загружал изображения, имена файлов теряются при отображении объекта, но если они вам нужны, вы можете просто использовать
cache
вместо этого объект напрямую, поскольку ключи - это имя файла.
// example with styles just for clarity
return (
<>
<p>Media Page..</p>
{Object.entries(cache).map(module => {
const image = module[1].default;
const name = module[0].replace("./","");
return (
<div style={{float: 'left', padding: 10, margin: 10, border: '2px solid white' }}>
<img style={{width: 100, margin: 'auto', display: 'block'}} src={image} />
<p>{name}</p>
</div>
)
})}
</>
);
ОБНОВЛЕНИЕ Кажется, я не совсем понял вопрос. @ Феликс понял все правильно, поэтому проверь его ответ. Следующий код будет работать только в среде Nodejs.
Добавить index.js
файл в images
папка
const testFolder = './';
const fs = require('fs');
const path = require('path')
const allowedExts = [
'.png' // add any extensions you need
]
const modules = {};
const files = fs.readdirSync(testFolder);
if (files && files.length) {
files
.filter(file => allowedExts.indexOf(path.extname(file)) > -1)
.forEach(file => exports[path.basename(file, path.extname(file))] = require(`./${file}`));
}
module.exports = modules;
Это позволит вам импортировать все из другого файла, а Wepback проанализирует его и загрузит необходимые файлы.