使用 webpack 从目录动态导入图像

下面是我目前通过 ES6在 webpack 中导入图片和图标的工作流程:

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']} />
119666 次浏览

很简单。您可以使用 require(一个静态的方法,导入只是为了动态文件)内的 render。比如下面的例子:

render() {
const {
someProp,
} = this.props


const graphImage = require('./graph-' + anyVariable + '.png')
const tableImage = require('./table-' + anyVariable2 + '.png')


return (
<img src={graphImage}/>
)
}

更新 我好像没有完全理解这个问题。@ Felix 答对了,看看他的答案。下面的代码只能在 Nodejs 环境中使用。

images文件夹中添加一个 index.js文件

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 将解析它并加载所需的文件。

我觉得一定有某种方法可以动态地从一个特定的目录中导入所有文件,作为它们的名称(不包含扩展名) ,然后根据需要使用这些文件。

ES6里没有。importexport的全部意义在于,依赖关系可以确定为 静止的,也就是说,不需要执行代码。

但是因为你正在使用 webpack,看一下 require.context。你应该能够做到以下几点:

function importAll(r) {
return r.keys().map(r);
}


const images = importAll(require.context('./', false, /\.(png|jpe?g|svg)$/));

我有一个名为 au.png、 nl.png 等 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;

解决这一问题的实用方法:

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)$/)
);

下面是我在 Reactjs 制作的一个功能组件,它使用 webpack 文档和这里的一些答案,简单地显示了我项目中 media文件夹内的所有图像(与组件的级别相同)。

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;

rendered images from media directory

按照我加载图像的方式,当从 cache对象映射时,文件名会丢失,但是如果你需要它们,你可以直接使用 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>
)
})}
</>
);

images with filenames