如何使用Vue的内置机制预取图像

15

我有一个使用Vue CLI的应用程序。当应用程序加载时,我会有一堆图片在用户点击按钮时出现转换效果。问题是,当用户点击按钮时,相应的图片才开始加载,这意味着大部分动画都完成了。这会使体验变得很卡顿,因为图片突然在过渡期间弹出,挤压其他元素。我希望在站点加载时先预取它们。

这个答案建议使用Image类。然而,根据Vue CLI文档,Vue在内部使用自己的插件preload-webpack-plugin,它显然可以配置

我试图配置它以预加载图片:

vue.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');

module.exports = {
  configureWebpack: {
    plugins: [
      new HtmlWebpackPlugin(),
      new PreloadWebpackPlugin({
        rel: 'prefetch',
        as (entry) {
          if (/\.css$/.test(entry)) return 'style';
          if (/\.woff$/.test(entry)) return 'font';
          if (/\.png$/.test(entry)) return 'image';
          return 'script';
        }
      })
    ]
  }
}

这只会破坏最终的index.html,导致其中没有构建脚本和样式。

如果我删除这行:

      new HtmlWebpackPlugin(),

该网站仍然可以加载,但图像未进行预取操作。这与我在vue.config.js文件中未做任何操作相同。
如何正确设置?

编辑:在Vue组件中,我使用require()来加载图片,这意味着它们会通过Webpack进行处理。例如:

<img :src="require('../assets/img/' + img)" draggable="false">

编辑: 我能够像Roy J在评论中建议的那样预取图像:

在我的主组件中,PreloadImages.vue:

<template>
  <div style="display: none;">
    <img :src="require('../assets/img/foo.png')">
    <img :src="require('../assets/img/bar.png')">
    <img :src="require('../assets/img/baz.png')">
  </div>
</template>

然而,这并不是我实际问题的答案——它没有使用通过<link>标签的资源提示。它还需要更多的努力,我认为这是一种不好的做法。

你链接的Vue文档似乎建议使用这种方式 - user5734311
你可以将图片包含在 <img> 标签中,放在不可见的地方吗? - Roy J
1
我想我可以,但我认为那是一个不好的解决方案。首先,我需要复制<img>标签,这不符合DRY原则。其次,路径是动态的,这使得事情变得更加复杂。 - dodov
当然,您会使img标签动态化,就像可见的那些一样。 - Roy J
但是这些图像是在SFC内部渲染的,而img变量是一个prop。我无法在组件外部访问该prop。此外,我不能将隐藏的<img>放在组件内部,因为它会在组件挂载时加载图像,这是没有意义的。 - dodov
显示剩余4条评论
2个回答

5

由于插件已经包含在VueJS中,因此我认为您需要使用chainWebpack进行修改。

根据文档,preload webpack插件应该将include选项设置为'allAssets'

在Webpack中,使用像file-loader这样的加载器来生成特定类型的资源(如字体或图像)非常常见。如果您希望预加载这些文件,可以使用值为allAssets的include。

因此,配置将类似于以下内容:

// vue.config.js
module.exports = {
    chainWebpack: config => {
        config.plugin('preload').tap(options => {
            options[0].as = (entry) => {
                if (/\.css$/.test(entry)) return 'style';
                if (/\.woff$/.test(entry)) return 'font';
                if (/\.png$/.test(entry)) return 'image';
                return 'script';
              }
            options[0].include = 'allAssets'
            // options[0].fileWhitelist: [/\.files/, /\.to/, /\.include/]
            // options[0].fileBlacklist: [/\.files/, /\.to/, /\.exclude/]
            return options
        })
    }
}

使用Vue-cli进行全新安装后,我得到了以下生成的HTML代码。
<!DOCTYPE html>
<html lang=en>

<head>
    <meta charset=utf-8>
    <meta http-equiv=X-UA-Compatible content="IE=edge">
    <meta name=viewport content="width=device-width,initial-scale=1">
    <link rel=icon href=/favicon.ico> <title>vue-preload-images</title>
    <link href=/css/app.0b9b292a.css rel=preload as=style>
    <!-- Here is the logo image -->
    <link href=/img/logo.82b9c7a5.png rel=preload as=image>
    <link href=/js/app.30d3ed79.js rel=preload as=script>
    <link href=/js/chunk-vendors.3d4cd4b5.js rel=preload as=script>
    <link href=/css/app.0b9b292a.css rel=stylesheet>
</head>

<body><noscript><strong>We're sorry but vue-preload-images doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript>
    <div id=app></div>
    <script src=/js/chunk-vendors.3d4cd4b5.js> </script> <script src=/js/app.30d3ed79.js> </script> </body> </html>

我希望这对你有用。


1

解决方案1。

当用户单击按钮时,您将图像呈现为非可见状态。

在图像的load事件中,您可以平稳地执行过渡效果。

如果图像加载通常需要超过2秒钟,请考虑给用户一个视觉线索,表明按钮单击已被记录,并且即将发生一些事情。

这将是技术上正确的解决方案。


解决方案2.

一种替代方案,广泛应用于生产环境(与Vue无关),是在页面中加载图像的缩略图(比原图小10倍左右,大小约为原图的1/100)。虽然不明显,但它们可以很好地替代大图,在过渡期间使用 - 您可能还想尝试对它们使用CSS blur滤镜。

缩略图和大图必须完全重叠,在相同的过渡父元素中,大图在下面。在大版本的load事件上,淡出缩略图,引起焦点效果:一个微妙的吸引眼球的效果。
这种方法的一个有趣的好处是,如果您将缩略图保持在顶部(opacity:0),每当有人尝试下载图像时,他们会右键单击缩略图,并难以理解为什么他们要下载低分辨率的图像。

除了在实际加载图像时添加焦点效果外,一切都基本相同(在动画方面)。

不是DRY,但很有效率。看起来专业,所有东西似乎都能立即顺畅加载。总体而言,它比其他“正确”的解决方案转化率更高。这就是为什么它常用于页面性能非常重要的网站上。
处理视觉时,“完美”意味着“看起来完美”(在用户体验中,也包括“感觉/看起来”完美)。古希腊人弯曲柱子,这样从下面看起来就是笔直的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接