详解vue中静态资源的路径问题(深度好文)

前言: webpack中的require解析

首先明确一点,在项目中的webpack.config.js等项目配置文件中使用的require属于nodejs范畴,而进入index.js后,加载的组件中的require都属于webpack的解析范畴。css

开始前,我们先聊聊webpack中require的用法。html

您可能以为这有什么,不就是直接require(url)直接引用吗,若是您这么想,那可就过小看require了。vue

let url = "@/assets/images/carousel/logo.svg"
require(url)    //报错

let url = "logo.svg"
require("@/assets/images/carousel/"+url); //正确

很诡异是否是? 我相信你第一次见到后会不自觉的说句f**k。node

这是由于你修改页面后,webpack进行编译,等待编译完,须要进行工程的打包,而后打包正确,才能热加载运行并刷新页面。
若是require中传入的是个变量,它有多是计算机系统中的任何目录下的任何文件,那么在打包静态资源时它有可能会将你的电脑整个磁盘遍历一遍(它很傻)。因此至少须要给出在哪一个路径下,这样才能精确的将那个路径下的对应文件打包,而后在代码运行时,直接用对应文件名生成正则匹配(由于打包后的文件,可能有hash值。不能直接查文件名),找到后,加载到代码中。webpack

因此,请记住 尽量详细的指定require中的路径,而后拼接变量web


接下来讲下打包后的路径问题
webpack将项目中的静态资源编译打包后,生成的路径已经不是原来的那个路径了。如
src/assets/image/logo.jpg
编译后可能变成
dist/public/image/logo.1d997ea3.jpgvue-cli

而经过require("src/assets/image/logo.jpg"),会自动找到并加载dist/public/image/logo.1d997ea3.jpg文件npm

1、<template>部分的路径处理

Vue Loader 在编译单文件组件中的 <template> 块时,它也会将全部遇到的资源 URL 转换为 webpack 模块请求。(这样咱们就不必手动调用require了,而是交给vue-loader处理了)ide

vue-loader默承认以处理的标签/特性的组合以下:svg

{
  video: ['src', 'poster'],
  img: 'src',   //即img元素上的src属性
  source: 'src',  //source元素上的src属性
  image: 'xlink:href'
}

面对上面的标签组合,vue-loader会自动进行资源url的转换。

转换规则:
a、若是路径是绝对路径,会被原样保留。如/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下了

b、若是路径以 . 开头,将会被看做相对的模块依赖。如 ./titlea.png

//代码
<img src="./titlea.png" alt="">

//渲染后html页面
<img data-v-70c98a68="" src="/static/img/titlea.1e9fa570.png" alt="">

c、若是路径以 @ 开头,也会被看做模块依赖。若是你的 webpack 配置中给 @ 配置了 alias,这就颇有用了。全部 vue-cli 建立的项目都默认配置了将 @ 指向 /src

//代码
<img src="@/assets/image/login/title.png" alt="">

//渲染后html页面
<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">

d、若是路径以 ~ 开头,其后的部分将会被看做模块依赖,既能够加载含有别名的静态资源,又能够加载node-modules中的资源。如

//代码
<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="">

2、<style>部分的路径处理

因为vue-loader在处理style时,采用的是style-loader,因此可能 和上面<template>部分的转换规则不太同样。
在vue-loader的内部使用了以下的配置(不必定配置,也有可能经过js直接给rules赋值):

//在vue-loader的内部使用css-loader
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: 'css-loader',
        options: {  
          url: true, //默认选项
        },
      },
    ],
  },
};

url为true时,则意味着能够将url中的字符串经过require()加载进来。

转换规则

//代码
<style scoped>
.login-wrap {
  background-image: url("/src/assets/image/login/title.png");
}
</style>

//渲染后css
.login-wrap[data-v-70c98a68] {
  background-image: url(/src/assets/image/login/title.png);
}

一样不会显示,编译后的路径不是这个
b、若是路径以 . 开头,将会被看做相对的模块依赖。如 ./titlea.png

//代码
<style scoped>
.login-wrap {
  background-image: url("./titlea.png");
}
</style>

//渲染后css
.login-wrap[data-v-70c98a68] {
  background-image: url(/static/img/titlea.1e9fa570.png);
}

c、若是路径以 ~ 开头,其后的部分将会被看做模块依赖,便可以加载含有别名的静态资源,又能够加载node-modules中的资源。如

//代码
<style scoped>
.login-wrap {
  background-image: url("~[npm包名]/logo.png");
}
</style>

//渲染后css
.login-wrap[data-v-70c98a68] {
  background-image: url(/static/img/logo.e05643fc.png);
}




//代码
<style scoped>
.login-wrap {
  background-image: url("~@/assets/image/login/bg.png");
}
</style>

//渲染后css
.login-wrap[data-v-70c98a68] {
  background-image: url(/static/img/bg.1d997ea3.png);
}

注意: 和上面的<template>相比,惟独少了直接用@开头的方式url("@/assett/logo.png"),因此下面写法是错误的

//代码
<style scoped>
.login-wrap {
  background-image: url("@/assets/image/login/bg.png");
}
</style>

感谢各位看客的阅读,因为在项目中遇到了这样的困然,再加上同事也常常问我什么缘由,故而填坑,以避免其余人踩坑。

相关文章
相关标签/搜索