最近修改一些老项目,好多组件里面引入图片的方式不太一样,总感觉自己没有好好总结过,今天有时间参考了几篇帖子,就总结一下;
在总结之前看了一下vue-cli的文档,突然感觉之前可能是我忽略它了基本没有看过,官方文档这块写的清清楚楚,还是应该多看文档,天天看掘金、简书这些碎片化知识也不太好;
Vue.js关于静态资源的官方文档
在 JavaScript 被导入或在 template/CSS 中被引用。
这类引用会被 webpack 处理。诸如<img src="...">
、background: url(...)
和CSS @import
的资源, 都会被解析为一个模块依赖。
例如,url(./image.png)会被翻译为require(’./image.png’)
放置在public目录下或通过绝对路径被引用。
这类资源将会直接被拷贝,而不会经过 webpack 的处理,你需要通过绝对路径来引用它们。
首先明确一点,在项目中的webpack.config.js等项目配置文件中使用的require属于nodejs范畴,而进入index.js后,加载的组件中的require都属于webpack的解析范畴。
先聊聊webpack中require的用法。
// 代码1 报错let url="@/assets/images/carousel/logo.svg"require(url)// require单纯传了一个变量// 代码2 正确let url="logo.svg"require("@/assets/images/carousel/"+url);// require里面虽然是变量但是增加了前缀,让计算机更快找到
页面修改webpack流程:
如果require中传入的是个变量,它有可能是计算机系统中的任何目录下的任何文件,那么在打包静态资源时它有可能会将你的电脑整个磁盘遍历一遍(它很傻); 如上代码1只传了个变量。
因此需要给出在大致路径(如上代码2),这样才能精确的将那个路径下的对应文件打包,然后在代码运行时,直接用对应文件名生成正则匹配(因为打包后的文件,可能有hash值。不能直接查文件名),找到后,加载到代码中。所以,尽可能详细的指定require中的路径,然后拼接变量。
webpack将项目中的静态资源编译打包后,生成的路径已经不是原来的那个路径了。
src/assets/image/logo.png// 编译后可能变成 dist/public/image/logo.1d997ea3.png通过require("src/assets/image/logo.png"), 会自动找到并加载 dist/public/image/logo.1d997ea3.png文件
关于打包完不是原来的路径那是 file-loader 的作用,这里不细说可以看一下,file-loader和url-loader的讲解。
这里主要用到 vue-loader,vue-loader 在编译单文件组件中的 块时,它也会将所有遇到的资源 URL 转换为 webpack 模块请求。(这样我们就没必要手动调用require了,而是交给vue-loader处理了)
vue-loader默认可以处理的标签/特性的组合如下: (不包括style)
// 面对下面的标签组合,vue-loader会自动进行资源url的转换。{ video:['src','poster'], img:'src',//即img元素上的src属性 source:'src',//source元素上的src属性 image:'xlink:href'}
/src/assets/image/login/title.png
//代码<template><img src="/src/assets/image/login/title.png" alt=""></template>//渲染后html页面<img data-v-70c98a68="" src="/src/assets/image/login/title.png" alt="">// 当然这个图片是无法展示的,因为编译后title.png已不在src/assets/image/login下了
这个图片是无法展示的,因为编译后title.png已不在src/assets/image/login
下了 ,关于public文件夹在下文会有介绍
//代码<img src="./titlea.png" alt="">//渲染后html页面<img data-v-70c98a68="" src="/static/img/titlea.1e9fa570.png" alt="">
❌错误的引入方式,使用 :src 调用了 v-bind 指令处理其内容,相对路径不会被webpack的 file-loader 处理。
<img:src="'./assets/images/02.jpg'" alt="">// ×// 编译后:<img src="./assets/images/02.jpg" alt="">
//代码<img src="@/assets/image/login/title.png" alt="">//渲染后html页面<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">
// 如果用别名的静态资源必须加@否则报一下错误。//代码 必须有@否则报错,@是别名<img src="~@/assets/image/login/title.png" alt="">//渲染后html页面<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">//代码<img src="~[npm包名]/xxx/logo.png" alt="">//渲染后的html页面<img data-v-70c98a68="" src="/static/img/logo.2f53e458.png" alt="">
<style>
部分的路径处理由于vue-loader在处理style时,采用的是style-loader,所以可能 和上面部分的转换规则不太一样。在vue-loader的内部使用了如下的配置(不一定配置,也有可能通过js直接给rules赋值):
//在vue-loader的内部使用css-loader module.exports={ module:{ rules:[{ test:/\.css$/, loader:'css-loader', options:{ url:true,//默认选项 url为true时,则意味着可以将url中的字符串通过require()加载进来。},},],},};
/src/assets/image/login/title.png
//代码<style scoped>.login{ background-image:url("/src/assets/image/login/title.png");}</style>//渲染后css.login[data-v-70c98a68]{ background-image:url(/src/assets/image/login/title.png);}// 同样不会显示,编译后的路径不是这个(要放在public下面)
//代码<style scoped>.login{ background-image:url("./title.png");}</style>//渲染后css.login[data-v-70c98a68]{ background-image:url(/static/img/title.1e9fa570.png);}
//代码<style scoped>.login{ background-image:url("~[npm包名]/logo.png");}</style>//渲染后css.login-[data-v-70c98a68]{ background-image:url(/static/img/logo.e05643fc.png);}//代码<style scoped>.login{ background-image:url("~@/assets/image/login/bg.png");// 和上面的<template>相比,少了直接用@开头的方式url("@/assett/logo.png")// 错误写法// background-image: url("@/assets/image/login/bg.png");}</style>//渲染后css.login[data-v-70c98a68]{ background-image:url(/static/img/bg.1d997ea3.png);}
require()
引入,在template
的:src
或者script
的data computed
中都可以进行 require 引入或拼接。<img:src="require('./assets/images/03.jpg')" alt="">// √<img:src="require('./assets/images/'+ this.imgName +'.jpg')" alt="">// √<img:src="img3" alt="">// √<script>exportdefault:{data(){return{ imgName:'03.jpg', img3:require('./assets/images/03.jpg'),// 或者 @是定义的别名,(注意这里可以直接用@,而在style中只能用~@) img3:require('@/assets/images/login-bg.png')}},}</script>// 编译后:<img src="/img/03.ea62525c.jpg" alt="">
<template><img:src="imgUrl"></template><script>import imgUrlfrom"../assets/test.png"</script>
<div:style="{ backgroundImage: `url(${img3})` }"></div><script>exportdefault:{data(){return{ img3:require('./assets/images/03.jpg'),// 或者 img3:require('@/assets/images/login-bg.png')}},}</script>
任何放置在public文件夹的静态资源都会被简单的复制,而不经过 webpack。你需要通过绝对路径来引用它们。
用绝对路径引入时,路径读取的是public
文件夹中的资源,任何放置在public
文件夹的静态资源都会被简单的复制到编译后的目录中,而不经过webpack
特殊处理。
当你的应用被部署在一个域名的根路径上时,比如http://www.abc.com/
,此时这种引入方式可以正常显示但是如果你的应用没有部署在域名的根部,那么你需要为你的 URL 配置publicPath
前缀 publicPath 是部署应用包时的基本 URL,在vue.config.js
中进行配置,详情参阅官方文档
// vue.config.js 应用没有部署到域名的根目录// 引入publicPath并且将其拼接在路径中,实现引入路径的动态变动 module.exports={ publicPath:'/foo/',...}
<img:src="this.publicPath + 'images/05.jpg'" alt="">// √// 编译后:<img src="/foo/images/05.jpg" alt=""><script>exportdefault:{data(){return{ publicPath: process.env.BASE_URL,}},}</script>
<img src="~some-npm-package/foo.png" alt="Vue中引入静态资源的几种方式">
推荐将资源作为你的模块依赖图的一部分导入,这样它们会通过 webpack 的处理并获得如下好处:
上一个:RMI反序列化学习