【 在vue中动态的引入图片为什么要使用require?】

在vue中动态的引入图片为什么要使用require?

先上答案总结

因为动态添加的src,编译过后的文件地址和被编译过后的资源文件地址不一致,从而无法正确引入资源。而使用require,返回的就是资源文件被编译后的文件地址,从而可以正确的引入资源。

探究过程

提到这个问题,有些小伙伴,可能会说:因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require。
乍一看好像说的很有道理啊,但是仔细一看,这句话说的到底是个啥?针对上面的回答,我不禁有如下几个疑问:
1、什么是静态资源?
2、为什么动态添加的src会被当做的静态的资源?
3、没有进行编译,是指为是什么没有被编译?
4、加上require为什么能正确的引入资源,是因为加上require就能编译了?

1.什么是静态资源

静态资源

一般客户端发送请求到web服务器,web服务器从内存在取到相应的文件,返回给客户端,客户端解析并渲染显示出来。

动态资源

一般客户端请求的动态资源,先将请求交于web容器,web容器连接数据库,数据库处理数据之后,将内容交给web服务器,web服务器返回给客户端解析渲染处理。


其实上面的总结已经很清晰了。站在一个vue项目的角度,我们可以简单的理解为:
静态资源就是直接存放在项目中的资源,这些资源不需要我们发送专门的请求进行获取。比如assets目录下面的图片,视频,音频,字体文件,css样式表等。
动态资源就是需要发送请求获取到的资源。比如我们刷淘宝的时候,不同的商品信息是发送的专门的请求获取到的,就可以称之为动态资源。

2. 为什么动态添加的src会被当做的静态的资源?

回答这个问题之前,我们需要了解一下,浏览器是怎么能运行一个vue项目的。
我们知道浏览器打开一个网页,实际上运行的是html,css,js三种类型的文件。当我们本地启动一个vue项目的时候,实际上是先将vue项目进行打包,打包的过程就是将项目中的一个个vue文件转编译成html,css,js文件的过程,而后再在浏览器上运行的。
那动态添加的src如果我们没有使用require引入,最终会打包成什么样子呢,我带大家实验一波。
// vue文件中动态引入一张图片

 <template>
  <div class="home">
      <!-- 通过v-bind引入资源的方式就称之为动态添加 -->
    <img :src="'../assets/logo1.png'" alt="logo">
  </div>
</template>

//最终编译的结果(浏览器上运行的结果)
//这张图片是无法被正确打开的

<img src="../assets/logo.png" alt="logo">  

我们可以看出,动态添加的src最终会编译成一个静态的字符串地址。程序运行的时候,会按照这个地址去项目目录中引入资源。而 去项目目录中引入资源的这种方式,就是将该资源当成了静态资源。所以这也就回答了我们的问题2。
看到这里估计就有小伙伴疑惑了,这个最终被编译的地址有什么问题吗?我项目中的图片就是这个地址,为什么无法引入?别急,我们继续往下看。

3. 没有进行编译,是指的是什么没有被编译?

没有进行编译。这半句话,就听得很让人懵逼了。按照问题2我们知道这个动态引入的图片最终是被编译了,只是被编译之后无法正确的引入图片资源而已。所以这句话本来就是错的。
针对于我们的标准答案,我在这里进行改写:
因为动态添加src被当做静态资源处理了,而被编译过后的静态路径无法正确的引入资源,所以要加上require
那这里就诞生了一个新的疑问:被编译过后的静态路径为什么无法正确的引入资源?
想得到这个问题的答案,我们得先从正常的引入一张图片开始。在项目中我们静态的引入一张图片肯定是可以引入成功的,而引用图片所在的vue文件肯定也是被编译的,那静态引入图片最终会被编译成什么样呢,模拟一波:
// vue文件中静态的引入一张图片

<template>
  <div class="home">
      <!-- 直接引入图片静态地址, 不再使用v-bind -->
    <img src="../assets/logo.png" alt="logo">
  </div>
</template>

//最终编译的结果
//这张图片是可以被正确打开的

<img src="/img/logo.6c137b82.png" alt="logo">

根据测试,我们发现,使用静态的地址去引入一张图片,图片的路径和图片的名称已经发生了改变,并且编译后过后的静态地址是可以成功的引入资源的。这是因为,在默认情况下,src目录下面的所有文件都会被打包,src下面的图片也会被打包在新的文件夹下并生成新的文件名。编译过后的静态地址引入的是打包过后的图片地址,从而可以正确的引用资源

到这里我们其实就可以解释上面的问题了:动态添加的src,被编译过后的静态路径为什么无法正确的引入资源?
因为动态的添加的src编译过后的地址,与图片资源编译过后的资源地址不一致, 导致无法正确的引入资源

  编译过后的src地址:../assets/logo.png
  编译过后的图片资源地址:/img/logo.6c137b82.png

那要怎么解决上述的问题呢,答案就是:require

4. 加上require为什么能正确的引入资源,是因为加上require就能编译了?

针对这个问题,首先就要否定后半句,无论加不加require,vue文件中引入一张图片都会被编译。
接着我们再来好好了解一下,require。

4.1 require是什么: 是一个node方法,用于引入模块,JSON或本地文件
4.2 调用require方法引入一张图片之后发生了什么:

在回答这个问题之前,容我先对问题3中的内容进行一定的补充。

vue项目最终会被webpack打包成一个dist目录。webpack打包的时候,对图片资源进行了相关的配置。默认的,对于小于8k的图片,会将图片转成base64 直接插入图片,不会再在dist目录生成新图片。对于大于8k的图片,会打包进dist目录,之后将新图片地址返回给src。

而webpack中的打包规则,针对的其实是一个一个模块,换而言之webpack只会对模块进行打包。那webpack怎么将图片当成一个模块呢,这就要用到我们的正主require。我们可以将require当成一个桥梁,使用了require方法引入的资源,该资源就会当成模块并根据配置文件进行打包,并返回最终的打包结果。

回到问题4.2:调用require方法引入一张图片之后发生了什么
1.如果这张图片小于项目中设置的资源限制大小,则会返回图片的base64插入到require方法的调用处
2.如果这张图片大于项目中设置的资源限制大小,则会将这个图片编译成一个新的图片资源。require方法返回新的图片资源路径及文件名
回到问题4:为什么加上require能正确的引入资源
因为通过require方法拿到的文件地址,是资源文件编译过后的文件地址(dist下生成的文件或base64文件),因此可以找对应的文件,从而成功引入资源。

答案就是这么简单,来验证一波
// vue文件中使用require动态的引入一张图片

<template>
  <div class="home">
      <!-- 使用require动态引入图片 -->
      <img :src="require('../assets/logo.png')" alt="logo">
  </div>
</template>

//最终编译的结果
//这张图片是可以被正确打开的

<img src="/img/logo.6c137b82.png" alt="logo">

图片
有问题吗,没有问题。到这里,不妨再对我们的标准答案进行一次优化:
因为动态添加的src,编译过后的文件地址和被编译过后的资源文件地址不一致,从而无法正确引入资源。而使用require,返回的就是资源文件被编译后的文件地址,从而可以正确的引入资源。

问题扩展

问题3中,静态的引入一张图片,没有使用require,为什么返回的依然是编译过后的文件地址?

答:在webpack编译的vue文件的时候,遇见src等属性会默认的使用require引入资源路径。引用vue-cli官方的一段原话

当你在 JavaScript、CSS 或 *.vue 文件中使用相对路径 (必须以 . 开
头) 引用一个静态资源时,该资源将会被包含进入 webpack 的依赖图中。
在编译过程中,所有诸如 <img src="...">、background: url(...) 
和 CSS @import 的资源 URL 都会被解析为一个模块依赖。

例如,url(./image.png) 会被翻译为 require(‘./image.png’),而:

<img src="./image.png">

将会被编译到:

h('img', { attrs: { src: require('./image.png') }})
动态添加src的时候也会使用require引入,为什么src编译过后的地址,与图片资源编译过后的资源地址不一致

答:因为动态引入一张图片的时候,src后面的属性值,实际上是一个变量。webpack会根据v-bind指令去解析src后面的属性值。并不会通过reuqire引入资源路径。这也是为什么需要手动的添加require。

据说public下面的文件不会被编译,那我们使用静态路径去引入资源的时候,也会默认的使用require引入吗?

答:不会,使用require引入资源的前提的该资源是webpack解析的模块,而public下的文件压根就不会走编译,也就不会使用到require。

为什么使用public下的资源一定要绝对路径

答:因为虽然public文件不会被编译,但是src下的文件都会被编译。由于引入的是public下的资源,不会走require,会直接返回代码中的定义的文件地址,该地址无法在编译后的文件目录(dist目录)下找到对应的文件,会导致引入资源失败。

webpack,为什么引入资源的时候要有base64和打包到dist目录下两种的方式,全部打包到的dist目录下,他不香吗?

答:为了减少http请求。页面中通过路径引入的图片,实际上都会向服务器发送一个请求拿到这张图片。对于资源较小的文件,设置成base64,既可以减少请求,也不会影响到页面的加载性能。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值