精华内容
下载资源
问答
  • vue动态添加style样式

    万次阅读 2019-08-22 02:28:49
    凡是有-的style属性名都要变成驼峰式,比如font-size要变成fontSize 除了绑定值,其他的属性名的值要用引号括起来,比如backgroundColor:'#00a2ff'而不是 backgroundColor:#00a2ff 【对象】 ...

    注意:

    • 凡是有-的style属性名都要变成驼峰式,比如font-size要变成fontSize
    • 除了绑定值,其他的属性名的值要用引号括起来,比如backgroundColor:'#00a2ff'而不是 backgroundColor:#00a2ff

    【对象】

    • html :style="{ color: activeColor, fontSize: fontSize + 'px' }"

    • html :style="{color:(index==0?conFontColor:'#000')}"

    【数组】

    • html :style="[baseStyles, overridingStyles]"
    • html :style="[{color:(index==0?conFontColor:'#000')},{fontSize:'20px'}]"

    【三目运算符】

    • html :style="{color:(index==0?conFontColor:'#000')}"
    • html :style="[{color:(index==0?conFontColor:'#000')},{fontSize:'20px'}]"

    【多重值】

    此时,浏览器会根据运行支持情况进行选择

    • html :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"

    【绑定data对象】

    • html :style="styleObject"
    data() {
        return{
          styleObject: {
            color: 'red',
            fontSize: '13px'
          }  
        }
    }
    复制代码

    转载于:https://juejin.im/post/5d5dfbde6fb9a06b122f4226

    展开全文
  • Macbook版Intellij IDEA 配置 Code Style

    万次阅读 2019-10-15 16:16:29
    先贴上Google的官方code style文档 Google Java Style Guide Google 在 GitHub 上有一个专门放置编码规范的仓库,地址在:https://github.com/google/styleguide 现在有了这两样东西,就可以开始配置了。 在git仓库...

    先贴上Google的官方code style文档
    Google Java Style Guide

    Google 在 GitHub 上有一个专门放置编码规范的仓库,地址在:https://github.com/google/styleguide

    现在有了这两样东西,就可以开始配置了。
    在git仓库里找到 intellij-java-google-style.xml 文件,打开它,然后copy到本地。

    好,现在我们进入Intellij IDEA,在左上角点击“IntelliJ IDEA“ -> preference
    在这里插入图片描述
    在侧边栏选择 Editor -> Code Style -> Java
    点击齿轮按钮,进入设置,inport刚刚保存的xml文件,Apply即可。

    注意:使用Google Style与Idea默认风格的最大区别是:

    1. 代码行最大宽度从120个字符减少到了100个
    2. 一个缩进从4个空格减少为2个
    展开全文
  • StyleGAN代码学习】StyleGAN模型架构

    千次阅读 多人点赞 2019-12-10 19:19:20
    完整StyleGAN笔记:http://www.gwylab.com/pdf/Note_StyleGAN.pdf 基于StyleGAN的一个好玩的网站:www.seeprettyface.com —————————————————————————————————    第二章 Style...

    完整StyleGAN笔记:http://www.gwylab.com/pdf/Note_StyleGAN.pdf

    基于StyleGAN的一个好玩的网站:www.seeprettyface.com
    —————————————————————————————————
      

    第二章 StyleGAN代码解读(上)

      这一章将对StyleGAN的代码进行非常细致的分析和解读。一方面有助于对StyleGAN的架构和原理有更深的认识,另一方面是觉得AdaIN的思想很有价值,希望把它写代码的技巧学习下来,以后应该在GANs中会有很多能用得上的地方(其它paper里挺多出现了AdaIN的地方)。含有中文注释的代码可以在这里获得。

    2.1 StyleGAN代码架构总览

    在这里插入图片描述
          图2.1 StyleGAN官方代码架构

      如图2.1所示,StyleGAN代码的封装与解耦做的非常细致,可见作者的代码功底是非常扎实的。简单来说,在dnnlib文件夹下封装了日志提交工具、tensorflow环境配置与网络处理工具以及一些杂项实用类函数,这个文件夹尽量不要去动;在metrics文件夹下定义了许多指标计算方法,包括FID、LS、PPL指标以及一些GANs的通用指标计算方法;而training文件夹是需重点关注的部分,里面包含了数据处理、模型架构、损失函数和训练过程等基于StyleGAN的核心内容,在接下来的笔记中也会重点对这一部分进行细致讲解;最后,在主目录下,有一些全局配置、功能展示和运行接口的代码,其中train.py值得细读一下,它是训练StyleGAN网络的主要切入点。
      在接下来的笔记中,将从三个部分解读StyleGAN的代码,分别是:模型架构、损失函数和训练过程。至于其它部分的代码,由于我并不是特别关注,就不再赘述了。

    2.2 网络架构代码解读

      StyleGAN的网络架构全都写在training/networks_stylegan.py下,主要包括四个组成部分(代码302行-659行):G_style(),G_mapping(),G_synthesis()和D_basic()。
    在这里插入图片描述
      如上图所示,G_style表示整个生成器的网络架构,它由两个子网络组成,分别是映射网络G_mapping和合成网络G_synthesis;然后D_basic表示整个判别器的网络架构,它沿用了ProGAN中的模型设计。

    2.2.1 G_style网络

      G_style网络位于代码302-379行。在G_style中定义的组件包括:参数验证->设置子网络->设置变量->计算映射网络输出->更新W的移动平均值->执行样式混合正则化->应用截断技巧->计算合成网络输出。其中设置子网络就是调用构建G_mapping和G_synthesis的过程,两个子网络的定义将在下两节介绍。
      · G_style输入参数(line303-315)
    在这里插入图片描述
      输入参数包括512维的Z码向量和条件标签(在FFHQ数据集上没有使用标签),和一些可选的参数,包括截断参数、计算移动平均值W时的参数、样式混合参数、网络状态参数和子网络的参数们等。

      · 参数验证(line318-330)
    在这里插入图片描述
      对输入参数进行验证,主要是对网络状态和其对截断率、W平均值衰减率和样式混合概率的关系之间进行验证。

      · 设置子网络(line333-338)
    在这里插入图片描述
      直接使用tflib.Network()类(充当参数化网络构建功能的便捷包装,提供多种实用方法并方便地访问输入/输出/权重)创建两个子网络,子网络的内容在后面的函数(func_name = G_synthesis或func_name = G_mapping)中被定义。

      · 设置变量(line341-342)
    在这里插入图片描述
      设置两个变量lod_in和dlatent_avg。前者决定当前处在第几层分辨率,即lod=resolution_log2–res(其中res表示当前层对应的分辨率级别(2-10));后者决定截断操作的基准,即生成人脸的dlatent码的平均值。

      · 计算映射网络输出(line345)
    在这里插入图片描述
      得到映射网络的输出,即中间向量W’。

      · 更新W的移动平均值(line348-353)
    在这里插入图片描述
      把batch的dlatent平均值朝着总dlatent平均值以dlatent_avg_beta步幅靠近,作为新的人脸dlatent平均值,即dlatent_avg。

      · 执行样式混合正则化(line356-366)
    在这里插入图片描述
      样式混合正则化其实很好理解,就是随机创建一个新的潜码,这个潜码以一定概率与原始潜码交换某一部分,对于交换后的混合潜码,其生成的图片也要能够逼真,这就是样式混合正则化的实现。

      · 应用截断技巧(line369-374)
    在这里插入图片描述
      截断是指,用平均脸dlatent_avg朝着当前脸dlatents以coefs步幅靠近,得到的结果就是截断的dlatents。

      · 计算合成网络输出(line377-379)
    在这里插入图片描述
      将截断的dlatents传给G_synthesis网络进行合成,得到的结果就是整个生成网络G_style的输出结果。

    2.2.2 G_mapping网络

    在这里插入图片描述
      G_mapping网络位于代码384-435行。如上图所示,G_mapping网络实现了从初始生成码到中间向量的映射过程。在G_mapping中定义的组件包括:输入->连接标签->归一化潜码->映射层->广播->输出。其中映射层由8个全连接层组成。

      · G_mapping输入参数(line385-398)
    在这里插入图片描述
      输入参数包括512维的Z码向量和条件标签(在FFHQ数据集上没有使用标签),和一些可选的参数,包括初始向量Z参数、中间向量W参数、映射层设置、激活函数设置、学习率设置以及归一化设置等。

      · 网络输入(line403-407)
    在这里插入图片描述
      处理好latent的大小和格式后,其值赋给x,即用x标识网络的输入。

      · 连接标签(line410-414)
    在这里插入图片描述
      原始StyleGAN是无标签训练集,这部分不会被调用。

      · 归一化潜码(line417-418)
    在这里插入图片描述
      pixel_norm()(line239-242)
    在这里插入图片描述
      逐像素归一化的实现方式为:x=x/√(1/N ∑_(i=0)(N-1)▒〖x_i〗2 +ϵ),其中ϵ=10^-8。
      为何要使用pixel_norm呢? Pixel norm,它是local response normalization的变种,具有避免生成器梯度爆炸的作用。Pixel norm沿着channel维度做归一化(axis=1),这样归一化的一个好处在于,feature map的每个位置都具有单位长度。这个归一化策略与作者设计的Generator输出有较大关系,注意到Generator的输出层并没有Tanh或者Sigmoid激活函数。

      · 映射层(line421-426)
    在这里插入图片描述
      构建了mapping_layers层映射层,每个映射层有三个组成部分:全连接层dense()、偏置函数apply_bias()和激活函数act()。
      1)全连接层dense()(line 154-159)
    在这里插入图片描述
      dense()函数中首先将输出全部展平以计算输出维度,然后调用get_weight()创建全连接层w,最后返回x与w的矩阵相乘的结果,作为dense()层的输出。
      get_weight()(line 135-149)
    在这里插入图片描述
      get_weight()函数是用来创建卷积层或完全连接层,且获取权重张量的函数。
      值得注意的是,get_weight()采用了He的初始化方法。He的初始化方法能够确保网络初始化的时候,随机初始化的参数不会大幅度地改变输入信号的强度。StyleGAN中不仅限初始状态scale而且也是实时scale。
      2)添加偏置apply_bias()(line 213-218)
    在这里插入图片描述
      对给定的激活张量施加偏差。
      3)激活函数act()(line 400)
    在这里插入图片描述
      激活函数采用mapping_nonlinearity的值,StyleGAN中选用’lrelu’,且增益值为√2。
      注意这儿的gain是一个增益值,增益值是指的非线性函数稳态时输入幅度与输出幅度的比值,通常被用来乘在激活函数之后使激活函数更加稳定。常见的增益值包括:Sigmoid推荐的增益值是1,Relu推荐的增益值是√2,LeakyRelu推荐的增益值是√(2/(1+〖negative_slope〗^2 ))

      · 广播(line429-431)
    在这里插入图片描述

      这儿只定义了简单的复制扩充,广播前x的维度是(?,512),广播后x的维度是(?,18,512)。

      · 输出(line 434-435)
    在这里插入图片描述
      广播后的中间向量,就是G_mapping网络的最终输出。

    2.2.3 G_synthesis网络

    在这里插入图片描述
      G_synthesis网络位于代码441-560行。如上图所示,G_synthesis网络实现了从广播得到的中间向量到生成图片的合成过程。在G_synthesis中定义的组件包括:预处理->主要输入->噪音输入->★每层层末的调制功能->早期层(4*4)结构->剩余层的block块->★网络增长变换过程->输出。其中,每层层末的调制功能是指的在卷积之后,融入噪音与样式控制的过程(上图的⊕与AdaIN过程);网络增长变换过程是指的在训练时期,合成网络的架构动态增长,以生成更高分辨率图片的过程。上述两个内容是重点值得学习的部分。

      · G_synthesis输入参数(line441-462)
    在这里插入图片描述
      输入参数包括512维的中间向量(W)和输出图片的分辨率及通道,和一些可选的参数,包括各层特征图的设置、样式/网络起始值/噪音设置、激活函数设置、数据处理设置以及网络增长架构的设置等。

      · 预处理(line464-474)
    在这里插入图片描述
      预处理部分除了进一步细化网络配置以外,还定义了两个函数——nf()返回在第stage层中特征图的数量;blur()对图片进行滤波模糊操作,有利于降噪,其中blur的函数实现方式为blur2d()。
      blur2d ()(line 96-106)
    在这里插入图片描述
      在blur2d()里定义了模糊的返回函数为_blur2d(),同时blur2d()的一阶导和二阶导也被定义了出来,都是直接使用_blur2d()函数作为近似。
      _blur2d ()(line 22-49)
    在这里插入图片描述
      _blur2d ()的实现主要有两个部分,第一个部分是对于卷积核的处理,包括维度的规范和归一化处理;第二个部分是模糊的实现,即用卷积核对x实行depthwise_conv2d卷积。
      注意:depthwise_conv2d与普通的卷积有些不同。普通的卷积对卷积核每一个out_channel的两个通道分别和输入的两个通道做卷积相加,得到feature map的一个channel,而depthwise_conv2d卷积对每一个对应的in_channel,分别卷积生成两个out_channel,所以获得的feature map的通道数量可以用in_channel * channel_multiplier来表达,这个channel_multiplier,就可以理解为卷积核的第四维。参见博客:https://blog.csdn.net/mao_xiao_feng/article/details/78003476

      · 主要输入(line 477-479)
    在这里插入图片描述
      主要输入除了dlatents_in之外,还有一个lod_in参数。lod_in是一个指定当前输入分辨率级别的参数,规定lod = resolution_log2 – res。lod_in在递归构建模型架构的部分中被使用。

      · 创建噪音(line 482-487)
    在这里插入图片描述
      最初创建噪音时,只是依据对应层的分辨率创建对应的shape,然后随机初始化即为一个噪音。

      · ★层末调制(含AdaIN,line490-501)
    在这里插入图片描述
      层末调制,是在每个block的卷积之后对特征的处理,包含6种(可选)内容:应用噪音apply_noise()、应用偏置apply_bias()、应用激活函数act()、逐像素归一化pixel_norm()、实例归一化instance_norm()和样式调制(AdaIN)style_mod()。其中apply_bias()、act()与pixel_norm()在前文中已提及过,下面将不再赘述。
      1)apply_noise()(line 270-278)
    在这里插入图片描述
      应用噪音,直接将噪音加在特征x上就行了,注意按channel叠加。
      2)instance_norm()(line 247-256)
    在这里插入图片描述
      实例归一化是一个在生成模型中应用非常广泛的归一化方式,它的主要特点是仅对特征的HW(高和宽)维度做归一化,对图像的风格影响明显。
      3)★style_mod ()(line 261-265)
    在这里插入图片描述
      样式控制(AdaIN)的代码只有3行。第1行是仿射变化A,它通过全连接层将dlatent扩大一倍;第2行将扩大后的dlatent转换为放缩因子y_(s,i)和偏置因子y_(b,i);第3行是将这两个因子对卷积后的x实施自适应实例归一化。

      · 早期层结构(line 504-514)
    在这里插入图片描述
      由于StyleGAN的网络结构随训练进行是动态变化的,所以代码中定义了训练最开始时的网络结构,即4*4分辨率的生成网络。StyleGAN的生成起点选用维度为(1,512,4,4)的常量,通过一个卷积层(conv2d)得到了通道数为nf(1)(即512维)的特征图。
      · conv2d(line 164-168)
    在这里插入图片描述
      conv2d通过简单的卷积实现,将x的通道数由x.shape[1]变为fmaps,而x的大小不变。

      · 剩余层的block块(line 517-527)
    在这里插入图片描述
      StyleGAN将剩余分辨率的网络层封装成了block函数,方便在训练过程中依据输入的res(由lod_in计算出来)实时构建及调整网络的架构。其中每个block都包括了一个上采样层(upscaled_conv2d)和一个卷积层,上采样层后置滤波处理与层末调制,卷积层后置层末调制。另外在训练过程中网络需实时输出图片,StyleGAN中定义了torgb()函数,负责将对应分辨率的特征图转换为RGB图像。
      · upscaled_conv2d()(line 174-191)
    在这里插入图片描述
      upscaled_conv2d利用tf.nn.conv2d_transpose反卷积操作实现将特征图放大一倍。其中一个值得注意的操作是,其卷积核被轻微平移了四次并对自身做了叠加,这样或许对于提取特征有帮助,但我查阅不到相关资料证明这一点。

      · ★网络增长变换过程(line 530-556)
      StyleGAN的生成网络需具备动态变换的能力,代码中定义了三种结构组合方式,分别是:固定结构、线性结构与递归结构。
      1)固定结构(line 530-533)
    在这里插入图片描述
      固定结构构建了直达1024*1024分辨率的生成器网络,简单高效但不支持渐进式增长。
      2)线性结构(line 536-544)
    在这里插入图片描述
      线性结构构建了upscale2d()的上采样层,能将当前分辨率放大一倍。另外在不同分辨率间变换时,线性结构采用了含大小值裁剪的线性插值,实现了不同分辨率下的平滑过渡。
      upscale2d()(line 108-118)
    在这里插入图片描述
      在upscale2d()里定义了上采样的返回函数为_upscale2d(),同时upscale2d()的一阶导和二阶导也被定义了出来,都是直接使用_upscale2d()函数作为近似。
      _upscale2d()(line 51-68)
    在这里插入图片描述
      _upscale2d()的实现使用了tf.tile()的骚操作,其实很简单,就是复制扩展了像素值。总而言之,线性结构的实现简单但效率低下。

      3)递归结构(line 547-556)
    在这里插入图片描述
      递归结构下定义了递归函数grow(),使得只需要调用一次grow()就能够实现所有分辨率层的构建。它的实现逻辑主要是:比较lod_in和lod的关系——当lod_in超过lod时,在同一层级上实现分辨率的线性扩增;当lod_in小于lod且不是最后一层时,跳转到下一级的分辨率层上。

      · 输出(line 558-559)
    在这里插入图片描述
      网络的最终输出为之前结构中得到的images_out。

      · G_style架构总览
      最后,通过一张G_style的完整网络架构图,让我们对各个层的名称、参数量、输入维度和输出维度有更具体的理解。
    在这里插入图片描述

    2.2.4 D_basic网络

    在这里插入图片描述
      D_basic网络位于代码566-661行。如上图所示,D_basic网络实现区分合成图片与真实图片的功能,沿用了ProGAN判别器的架构,基本上是生成器反过来的样子。在D_basic中定义的组件包括:预处理->构建block块->★网络增长变换过程->标签计算->输出。其中,网络增长变换过程是指的在训练时期,随着生成图片的分辨率提升,判别网络的架构动态增长的过程。另外,标签计算是指在训练集使用了含标签数据时,会将标签值与判别分数的乘积作为最终判别网络的输出值。

      · D_basic输入参数(line565-582)
    在这里插入图片描述
      输入参数包括图片、标签以及这二者的相关配置,和一些可选的参数,包括各层特征图的设置、激活函数设置、小批量标准偏差层设置、数据处理设置以及网络增长架构的设置等。

      · 预处理(line584-596)
    在这里插入图片描述
      预处理主要包括细化网络配置、输入数据的处理以及输出数据的定义,包含内容与G_synthesis中的预处理过程类似。

      · 构建block块(line 599-618)
    在这里插入图片描述
      在训练过程中网络需实时处理图片,StyleGAN中定义了fromrgb()函数,负责将对应分辨率的RGB图像转换为特征图。
      在block函数中,当分辨率不低于88时,一个block包含一个卷积层和一个下采样层(conv2d_downscale2d);而当分辨率为最开始的44时,一个block包含一个小批量标准偏差层(minibatch_stddev_layer)、一个卷积层和两个全连接层。
      conv2d_downscale2d()(line 193-208)
    在这里插入图片描述
      conv2d_downscale2d利用tf.nn.conv2d卷积操作实现将特征图缩小一倍。其中一个值得注意的操作是,其卷积核被轻微平移了四次并对自身做了叠加然后取平均值,这样或许对于提取特征有帮助,但我查阅不到相关资料证明这一点。
      minibatch_stddev_layer()(line 283-296)
    在这里插入图片描述
      在4*4分辨率的block中,构建了一个小批量标准偏差层,将特征图标准化处理,这样能让判别网络收敛得更快。

      · ★网络增长变换过程(line 621-650)
      StyleGAN的判别网络需具备动态变换的能力,代码中定义了三种结构组合方式,分别是:固定结构、线性结构与递归结构。
      1)固定结构(line 621-625)
    在这里插入图片描述
      固定结构构建了直达10241024分辨率的判别器网络,简单高效但不支持渐进式增长。
      2)线性结构(line 628-638)
    在这里插入图片描述
      线性结构构建了downscale2d()的下采样层,能将当前分辨率缩小一倍。另外在不同分辨率间变换时,线性结构采用了含大小值裁剪的线性插值,实现了不同分辨率下的平滑过渡。
      downscale2d()(line 120-130)
    在这里插入图片描述
      在downscale2d()里定义了下采样的返回函数为_downscale2d(),同时downscale2d()的一阶导和二阶导也被定义了出来,都是直接使用_downscale2d ()函数作为近似。
      _downscale2d()(line 70-90)
    在这里插入图片描述
      _downscale2d()中,如果卷积核大小为2
    2,则直接返回_blur2d()的结果;否则采用平均池化的方式实现下采样。

      3)递归结构(line 641-650)
    在这里插入图片描述
      递归结构下定义了递归函数grow(),使得只需要调用一次grow()就能够实现所有分辨率层的构建。它的实现逻辑比较复杂,请参见代码注释;值得注意的是,构建判别网络时是lod从大往小构建,所以递归的过程是与生成器相反的。
      · 标签计算(line 653-655)
    在这里插入图片描述
      如果使用了标签的话,将标签值与判别分数的乘积作为最终判别网络的输出值。

      · 输出(line 657-659)
    在这里插入图片描述
      网络的最终输出为scores_out。

      · D_basic架构总览
      最后,通过一张D_basic的完整网络架构图,让我们对各个层的名称、参数量、输入维度和输出维度有更具体的理解。
    在这里插入图片描述

    展开全文
  • 一文让你彻底弄懂 “vue-style-loader” 跟 “style-loader” 区别 简介 用过 vue-cli 脚手架搭建 vue 项目都知道,vue-cli 中内置了 vue-style-loader 去加载样式模块,最后通过 <style> 标签把样式加载到...

    简介

    用过 vue-cli 脚手架搭建 vue 项目都知道,vue-cli 中内置了 vue-style-loader 去加载样式模块,最后通过 <style> 标签把样式加载到页面,但是 style-loader 同样可以达到同样的效果,那么 vue 官方为啥还封装一个 vue-style-loader 库呢?那么它们到底有啥区别?平时项目中又该如何选择呢?

    开始

    为了更好的去分析这两个库,我们简单的搭建一个 vue 项目。

    其实如果对 webpack 很熟悉的话,从 0 开始搭建一个 vue 项目就很简单了,所以强烈推荐大家去看一下我上一篇 webpack 的文章,来和 webpack 谈场恋爱吧

    首先创建一个目录叫 style-loader-demo,然后初始化 npm

    mkdir style-loader-demo && cd style-loader-demo && npm init
    

    接下来我们需要安装 webpack 相关的依赖:

    安装 webpack

    webpack 核心库。

    在工程目录 style-loader-demo 执行以下命令安装 webpack:

    npm install -D webpack --registry https://registry.npm.taobao.org
    

    安装 webpack-cli

    webpack 指令库。

    在工程目录 style-loader-demo 执行以下命令:

    npm install -D webpack-cli --registry https://registry.npm.taobao.org
    

    安装 webpack-dev-server

    webpack 开发者服务框架。

    在工程目录 style-loader-demo 执行以下命令:

    npm install -D webpack-dev-server --registry https://registry.npm.taobao.org
    

    安装 webpack-chain

    webpack 配置工具。

    在工程目录 style-loader-demo 执行以下命令:

    npm install -D webpack-chain --registry https://registry.npm.taobao.org
    

    创建 webpack 配置

    在工程目录 style-loader-demo 下创建一个 webpack.config.js 文件:

    touch webpack.config.js
    

    然后对 webpack.config.js 进行配置,用 webpack-chain 导入一个 webpack 配置:

    const config = new (require('webpack-chain'))();
    
    module.exports = config.toConfig();
    

    为了开发方便,我们在 package.json 中声明两个脚本 builddev

    {
      "name": "style-loader-demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "rimraf dist && webpack --mode=production",
        "dev": "webpack-dev-server --mode=development --progress"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "css-loader": "^5.0.0",
        "html-webpack-plugin": "^4.5.0",
        "style-loader": "^2.0.0",
        "vue-style-loader": "^4.1.2",
        "webpack": "^4.44.2",
        "webpack-chain": "^6.5.1",
        "webpack-cli": "^3.3.12",
        "webpack-dev-server": "^3.11.0"
      },
      "dependencies": {
        "vue": "^2.6.12",
        "vue-loader": "^15.9.3",
        "vue-template-compiler": "^2.6.12"
      }
    }
    

    入口与出口

    我们首先在工程目录 style-loader-demo 下创建一个 src 目录,然后在 src 目录下创建一个 main.s 文件:

    mkdir src && cd src && touch main.js && cd ..
    

    然后我们找到 webpack.config.js 文件,对 webpack 的入口和出口进行配置:

    const path = require('path');
    const config = new (require('webpack-chain'))();
    config
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
            .entry('app') // 入口文件名称为 app
            .add('./src/main.js') // 入口文件为 ./src/main.ts
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename('[name].[hash:8].js') // 打包出来的 bundle 名称为 "[name].[hash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
    

    安装 vue

    vue 核心 API。

    npm install vue --registry https://registry.npm.taobao.org
    

    安装 vue-loader

    .vue 文件加载器。

    npm install vue-loader --registry https://registry.npm.taobao.org
    

    安装 vue-template-compiler

    .vue 文件模版解析器。

    npm install vue-template-compiler --registry https://registry.npm.taobao.org
    

    安装 html-webpack-plugin

    npm install -D html-webpack-plugin --registry https://registry.npm.taobao.org
    

    接下来我们在工程目录 sy_webpack-wedding 底下创建一个 public 目录,然后在 public 目录下创建一个 index.html 文件作为我们 app 的入口页面:

    mkdir public && touch public/index.html
    

    然后将以下内容写入 public/index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <title>Title</title>
      </head>
      <body>
        <noscript>your browser should support javascript!</noscript>
        <div id="app"></div>
        <!-- html-webpack-plugin 将自动引入入口文件 -->
      </body>
    </html>
    

    安装 css-loader

    css 模块加载器。

    npm install -D css-loader --registry https://registry.npm.taobao.org
    

    安装 vue-style-loader

    npm install -D vue-style-loader --registry https://registry.npm.taobao.org
    

    安装 style-loader

    npm install -D style-loader --registry https://registry.npm.taobao.org
    

    配置 webpack.config.js

    webpack 配置全部内容:

    const path = require('path');
    const config = new (require('webpack-chain'))();
    config
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
        .entry('app') // 入口文件名称为 app
            .add('./src/main.js') // 入口文件为 ./src/main.ts
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename('[name].[hash:8].js') // 打包出来的 bundle 名称为 "[name].[hash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions
                .add('.js')
                .add('.vue') // 配置以 .js 等结尾的文件当模块使用的时候都可以省略后缀
                .end()
            .end()
        .module
            .rule('vue') // vue-loader 相关配置
                .test(/\.vue$/) // 匹配 .vue 文件
                .use('vue-loader')
                    .loader('vue-loader')
                    .end()
                .end()
            .rule('css') // css-loader 相关配置
                .test(/\.css$/)
                .use('vue-style-loader')
                    .loader('vue-style-loader')
                    .end()
                .use('css-loader')
                    .loader('css-loader')
                    .options({
                        esModule: false
                    })
                    .end()
                .end()
            .end()
        .plugin('vue-loader-plugin') // vue-loader 必须要添加 vue-loader-plugin
            .use(require('vue-loader').VueLoaderPlugin, [])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true);
    module.exports = config.toConfig();
    

    测试

    我们在 src 目录下创建一个 app.vue 文件:

    touch src/app.vue
    

    然后将以下内容写入其中:

    <template>
        <div class="app">{{ msg }}</div>
    </template>
    
    <script>
    export default {
        name: "app",
        data(){
            return {
                msg: "hello"
            }
        }
    }
    </script>
    <style scoped>
        .app {
            color: red;
        }
    </style>
    

    很简单,就是一个简单的 vue 文件。

    然后在 main.js 中引入 app.vue 文件:

    import Vue from 'vue';
    import App from './app.vue';
    new Vue({
        el: '#app',
        render: (h) => h(App),
    });
    

    ok!一切准备完毕后,我们直接在工程目录运行 npm run dev 命令:

    npm run dev
    

    运行完毕后浏览器打开:
    在这里插入图片描述

    跟不上的童鞋可以直接下载源码:https://gitee.com/vv_bug/style-loader-demo

    vue-style-loader

    官网地址:https://github.com/vuejs/vue-style-loader

    This is a fork based on style-loader. Similar to style-loader, you can chain it after css-loader to dynamically inject CSS into the document as style tags. However, since this is included as a dependency and used by default in vue-loader, in most cases you don’t need to configure this loader yourself.

    意思大概是:“基于 style-loader fork 过来的,跟 style-loader 类似。”

    官网解释的还是比较敷衍的,我们结合 Demo 继续往下看。

    看一下现在的设置,我们找到 webpack.config.js

    const path = require('path');
    const config = new (require('webpack-chain'))();
    config
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
        .entry('app') // 入口文件名称为 app
            .add('./src/main.js') // 入口文件为 ./src/main.ts
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename('[name].[hash:8].js') // 打包出来的 bundle 名称为 "[name].[hash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions
                .add('.js')
                .add('.vue') // 配置以 .js 等结尾的文件当模块使用的时候都可以省略后缀
                .end()
            .end()
        .module
            .rule('vue') // vue-loader 相关配置
                .test(/\.vue$/) // 匹配 .vue 文件
                .use('vue-loader')
                    .loader('vue-loader')
                    .end()
                .end()
            .rule('css') // css-loader 相关配置
                .test(/\.css$/)
                .use('vue-style-loader')
                    .loader('vue-style-loader')
                    .end()
                .use('css-loader')
                    .loader('css-loader')
                    .options({
                        esModule: false
                    })
                    .end()
                .end()
            .end()
        .plugin('vue-loader-plugin') // vue-loader 必须要添加 vue-loader-plugin
            .use(require('vue-loader').VueLoaderPlugin, [])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true);
    module.exports = config.toConfig();
    

    再看一下现在的样式,我们找到 src/app.vue 文件:

    <style scoped>
        .app {
            color: red;
        }
    </style>
    

    上面的样式到底是怎样起作用的呢?

    首先经过 vue-loader 处理一遍变成了这样:

    .app[data-v-5ef48958] {
        color: red;
    }
    

    可以看到,我们样式经过 vue-loader 处理后加上了一个 “data-v-5ef48958”,这是为什么呢?因为我们在 style 标签上加了 scoped 标记:

    <style scoped>
    

    所以 vue-loader 会给所有的样式都加上一个 scoped 的属性。

    vue-loader 处理过后就到了 css-loader,经过 css-loader 处理后:

    // Imports
    var ___CSS_LOADER_API_IMPORT___ = require("../node_modules/css-loader/dist/runtime/api.js");
    var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});
    // Module
    ___CSS_LOADER_EXPORT___.push([module.id, "\n.app[data-v-5ef48958] {\n    color: red;\n}\n", ""]);
    // Exports
    module.exports = ___CSS_LOADER_EXPORT___;
    
    

    可以看到,css-loader 处理过后会把样式都变成 module 形式,然后直接导出这个模块,模块中包含了 css 的源码跟模块的 id。

    css-loader 处理过后会被 vue-style-loader 引用:

    // style-loader: Adds some css to the DOM by adding a <style> tag
    
    // load the styles
    var content = require("!!../node_modules/css-loader/dist/cjs.js??ref--1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/vue-loader/lib/index.js??vue-loader-options!./app.vue?vue&type=style&index=0&id=5ef48958&scoped=true&lang=css&");
    if(typeof content === 'string') content = [[module.id, content, '']];
    if(content.locals) module.exports = content.locals;
    // add the styles to the DOM
    var add = require("!../node_modules/vue-style-loader/lib/addStylesClient.js").default
    var update = add("d929f8d0", content, false, {});
    // Hot Module Replacement
    if(module.hot) {
     // When the styles change, update the <style> tags
     if(!content.locals) {
       module.hot.accept("!!../node_modules/css-loader/dist/cjs.js??ref--1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/vue-loader/lib/index.js??vue-loader-options!./app.vue?vue&type=style&index=0&id=5ef48958&scoped=true&lang=css&", function() {
         var newContent = require("!!../node_modules/css-loader/dist/cjs.js??ref--1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/vue-loader/lib/index.js??vue-loader-options!./app.vue?vue&type=style&index=0&id=5ef48958&scoped=true&lang=css&");
         if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
         update(newContent);
       });
     }
     // When the module is disposed, remove the <style> tags
     module.hot.dispose(function() { update(); });
    }
    

    上面代码中的 content 就是 css-loader 处理过后的模块。

    我们看一下 update 方法的声明:

    ...
    var add = require("!../node_modules/vue-style-loader/lib/addStylesClient.js").default
    var update = add("d929f8d0", content, false, {});
    ...
    

    可以看到,update 方法是通过 add 方法构建的,add 方法又是通过 !../node_modules/vue-style-loader/lib/addStylesClient.js 文件导入的,所以我们找到 !../node_modules/vue-style-loader/lib/addStylesClient.js 文件,我们直接定位到 xx/style-loader-demo/node_modules/vue-style-loader/lib/addStylesClient.js 文件:

    ...
    var ssrIdKey = 'data-vue-ssr-id'
    function createStyleElement () {
      var styleElement = document.createElement('style')
      styleElement.type = 'text/css'
      head.appendChild(styleElement)
      return styleElement
    }
    
    function addStyle (obj /* StyleObjectPart */) {
      var update, remove
      var styleElement = document.querySelector('style[' + ssrIdKey + '~="' + obj.id + '"]')
    
      if (styleElement) {
        if (isProduction) {
          // has SSR styles and in production mode.
          // simply do nothing.
    ...
    
    

    可以看到,其实就是创建了一个 style 标签,然后直接插入到了 head 标签中,但是 vue-style-loader 除了插入 style 外,还做了一些服务端渲染的支持,所以如果你的 vue 项目是需要支持服务端渲染的时候,就需要用到 vue-style-loader了,原理是不是很简单呢?

    style-loader

    官网地址:https://github.com/webpack-contrib/style-loader

    Inject CSS into the DOM.

    哈哈,无语了,style-loader 甚至都懒得解释了。

    ok!既然两位大佬官网都懒得解释了,那我们就只能自己去结合 Demo 看源码了。

    我们先用一下 style-loader,我们修改一下 webpack.config.js 文件:

    const path = require('path');
    const config = new (require('webpack-chain'))();
    config
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
        .entry('app') // 入口文件名称为 app
            .add('./src/main.js') // 入口文件为 ./src/main.ts
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename('[name].[hash:8].js') // 打包出来的 bundle 名称为 "[name].[hash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions
                .add('.js')
                .add('.vue') // 配置以 .js 等结尾的文件当模块使用的时候都可以省略后缀
                .end()
            .end()
        .module
            .rule('vue') // vue-loader 相关配置
                .test(/\.vue$/) // 匹配 .vue 文件
                .use('vue-loader')
                    .loader('vue-loader')
                    .end()
                .end()
            .rule('css') // css-loader 相关配置
                .test(/\.css$/)
                .use('style-loader')
                    .loader('style-loader')
                    .end()
                .use('css-loader')
                    .loader('css-loader')
                    .options({
                        esModule: false
                    })
                    .end()
                .end()
            .end()
        .plugin('vue-loader-plugin') // vue-loader 必须要添加 vue-loader-plugin
            .use(require('vue-loader').VueLoaderPlugin, [])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true);
    module.exports = config.toConfig();
    

    可以看到,我们把 vue-style-loader 换成了 style-loader:

    ...
    .rule('css') // css-loader 相关配置
                .test(/\.css$/)
                .use('style-loader')
                    .loader('style-loader')
                    .end()
                .use('css-loader')
                    .loader('css-loader')
                    .options({
                        esModule: false
                    })
                    .end()
    ...
    

    然后再次运行一下 npm run dev 命令看效果:

    npm run dev
    

    在这里插入图片描述
    可以看到,跟 vue-style-loader 的效果是一样的,这是为什么呢?

    跟前面 vue-style-loader 分析方式一样,我们先看一下现在的样式,我们找到 src/app.vue 文件:

    <style scoped>
        .app {
            color: red;
        }
    </style>
    

    上面的样式到底是怎样起作用的呢?

    首先经过 vue-loader 处理一遍变成了这样:

    .app[data-v-5ef48958] {
        color: red;
    }
    

    可以看到,我们样式经过 vue-loader 处理后加上了一个 “data-v-5ef48958”,这是为什么呢?因为我们在 style 标签上加了 scoped 标记:

    <style scoped>
    

    所以 vue-loader 会给所有的样式都加上一个 scoped 的属性。

    vue-loader 处理过后就到了 css-loader,经过 css-loader 处理后:

    // Imports
    var ___CSS_LOADER_API_IMPORT___ = require("../node_modules/css-loader/dist/runtime/api.js");
    var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});
    // Module
    ___CSS_LOADER_EXPORT___.push([module.id, "\n.app[data-v-5ef48958] {\n    color: red;\n}\n", ""]);
    // Exports
    module.exports = ___CSS_LOADER_EXPORT___;
    
    

    可以看到,css-loader 处理过后会把样式都变成 module 形式,然后直接导出这个模块,模块中包含了 css 的源码跟模块的 id。

    到这里其实都跟前面 vue-style-loader 方式一样。

    css-loader 处理过后会被 style-loader 引用,代码变成了这样:

    import api from "!../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js";
                import content from "!!../node_modules/css-loader/dist/cjs.js??ref--1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/vue-loader/lib/index.js??vue-loader-options!./app.vue?vue&type=style&index=0&id=5ef48958&scoped=true&lang=css&";
    
    var options = {};
    
    options.insert = "head";
    options.singleton = false;
    
    var update = api(content, options);
    
    
    if (module.hot) {
      if (!content.locals || module.hot.invalidate) {
        var isEqualLocals = function isEqualLocals(a, b, isNamedExport) {
      if (!a && b || a && !b) {
        return false;
      }
    
      var p;
    
      for (p in a) {
        if (isNamedExport && p === 'default') {
          // eslint-disable-next-line no-continue
          continue;
        }
    
        if (a[p] !== b[p]) {
          return false;
        }
      }
    
      for (p in b) {
        if (isNamedExport && p === 'default') {
          // eslint-disable-next-line no-continue
          continue;
        }
    
        if (!a[p]) {
          return false;
        }
      }
    
      return true;
    };
        var oldLocals = content.locals;
    
        module.hot.accept(
          "!!../node_modules/css-loader/dist/cjs.js??ref--1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/vue-loader/lib/index.js??vue-loader-options!./app.vue?vue&type=style&index=0&id=5ef48958&scoped=true&lang=css&",
          function () {
            if (!isEqualLocals(oldLocals, content.locals, undefined)) {
                    module.hot.invalidate();
    
                    return;
                  }
    
                  oldLocals = content.locals;
    
                  update(content);
          }
        )
      }
    
      module.hot.dispose(function() {
        update();
      });
    }
    
    export default content.locals || {};
    

    可以看到,上面的代码:

    import api from "!../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js";
                import content from "!!../node_modules/css-loader/dist/cjs.js??ref--1-1!../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../node_modules/vue-loader/lib/index.js??vue-loader-options!./app.vue?vue&type=style&index=0&id=5ef48958&scoped=true&lang=css&";
    ...
    

    content 就是 css-loader 处理过后的 css样式模块,包含了 css 源码跟 moduleid,那么 这里的 api 是啥呢?我们找到 xxx/style-loader-demo/node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 文件:

    ...
    function insertStyleElement(options) {
      var style = document.createElement('style');
      var attributes = options.attributes || {};
    
      if (typeof attributes.nonce === 'undefined') {
        var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;
    
        if (nonce) {
          attributes.nonce = nonce;
        }
      }
    
      Object.keys(attributes).forEach(function (key) {
        style.setAttribute(key, attributes[key]);
      });
    
      if (typeof options.insert === 'function') {
        options.insert(style);
      } else {
        var target = getTarget(options.insert || 'head');
    
        if (!target) {
          throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
        }
    
        target.appendChild(style);
      }
    
      return style;
    }
    
    function removeStyleElement(style) {
      // istanbul ignore if
      if (style.parentNode === null) {
        return false;
      }
    
      style.parentNode.removeChild(style);
    }
    /* istanbul ignore next  */
    
    
    var replaceText = function replaceText() {
      var textStore = [];
      return function replace(index, replacement) {
        textStore[index] = replacement;
        return textStore.filter(Boolean).join('\n');
      };
    }();
    
    function applyToSingletonTag(style, index, remove, obj) {
      var css = remove ? '' : obj.media ? "@media ".concat(obj.media, " {").concat(obj.css, "}") : obj.css; // For old IE
    
      /* istanbul ignore if  */
    
      if (style.styleSheet) {
        style.styleSheet.cssText = replaceText(index, css);
      } else {
        var cssNode = document.createTextNode(css);
        var childNodes = style.childNodes;
    
        if (childNodes[index]) {
          style.removeChild(childNodes[index]);
        }
    
        if (childNodes.length) {
          style.insertBefore(cssNode, childNodes[index]);
        } else {
          style.appendChild(cssNode);
        }
      }
    }
    
    function applyToTag(style, options, obj) {
      var css = obj.css;
      var media = obj.media;
      var sourceMap = obj.sourceMap;
    
      if (media) {
        style.setAttribute('media', media);
      } else {
        style.removeAttribute('media');
      }
    
      if (sourceMap && typeof btoa !== 'undefined') {
        css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
      } // For old IE
    
      /* istanbul ignore if  */
    
    
      if (style.styleSheet) {
        style.styleSheet.cssText = css;
      } else {
        while (style.firstChild) {
          style.removeChild(style.firstChild);
        }
    
        style.appendChild(document.createTextNode(css));
      }
    }
    
    var singleton = null;
    var singletonCounter = 0;
    
    function addStyle(obj, options) {
      var style;
      var update;
      var remove;
    
      if (options.singleton) {
        var styleIndex = singletonCounter++;
        style = singleton || (singleton = insertStyleElement(options));
        update = applyToSingletonTag.bind(null, style, styleIndex, false);
        remove = applyToSingletonTag.bind(null, style, styleIndex, true);
      } else {
        style = insertStyleElement(options);
        update = applyToTag.bind(null, style, options);
    
        remove = function remove() {
          removeStyleElement(style);
        };
      }
    
      update(obj);
      return function updateStyle(newObj) {
        if (newObj) {
          if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {
            return;
          }
    
          update(obj = newObj);
        } else {
          remove();
        }
      };
    }
    
    module.exports = function (list, options) {
      options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
      // tags it will allow on a page
    
      if (!options.singleton && typeof options.singleton !== 'boolean') {
        options.singleton = isOldIE();
      }
    
      list = list || [];
      var lastIdentifiers = modulesToDom(list, options);
      return function update(newList) {
        newList = newList || [];
    
        if (Object.prototype.toString.call(newList) !== '[object Array]') {
          return;
        }
    
        for (var i = 0; i < lastIdentifiers.length; i++) {
          var identifier = lastIdentifiers[i];
          var index = getIndexByIdentifier(identifier);
          stylesInDom[index].references--;
        }
    
        var newLastIdentifiers = modulesToDom(newList, options);
    
        for (var _i = 0; _i < lastIdentifiers.length; _i++) {
          var _identifier = lastIdentifiers[_i];
    
          var _index = getIndexByIdentifier(_identifier);
    
          if (stylesInDom[_index].references === 0) {
            stylesInDom[_index].updater();
    
            stylesInDom.splice(_index, 1);
          }
        }
    
        lastIdentifiers = newLastIdentifiers;
      };
    };
    

    可以看到,其实跟 vue-style-loader 一样,也是往 head 标签中注入一个 style 标签:
    在这里插入图片描述
    但是 style-loader 除了支持普通的注入 style 外,还支持以下模式:

    • linkTag:生成一个 link 标签,把 css-loader 处理过后的值赋给 link 标签的 href 属性。
    • lazyStyleTag & lazySingletonStyleTag:懒注入 style 标签。
    • styleTag & singletonStyleTag:默认方式,直接注入 style 标签。

    ok!我们拿一种方式操作一下,我们用一下 lazySingletonStyleTag

    首先我们创建一个 loaders 目录,然后在 loaders 目录下创建一个 customer-style-loader.js 文件:

    mkdir loaders && touch loaders/customer-style-loader.js
    

    然后将以下代码写入 loaders/customer-style-loader.js 文件:

    module.exports=function (source) {
        return `
            ${source}
            setTimeout(()=>{
                alert("来来来,show style!")
                exported && exported.use && exported.use();
            },5000);
        `;
    }
    

    可以看到,我们延迟了 5s 去显示我们的样式,然后我们找到 webpack.config.js 引入我们的 customer-style-loader.js,并且把 style-loader 的 injectType 设置成 lazySingletonStyleTag

    const path = require('path');
    const config = new (require('webpack-chain'))();
    config
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
            .entry('app') // 入口文件名称为 app
            .add('./src/main.js') // 入口文件为 ./src/main.ts
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename('[name].[hash:8].js') // 打包出来的 bundle 名称为 "[name].[hash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions
                .add('.js')
                .add('.vue') // 配置以 .js 等结尾的文件当模块使用的时候都可以省略后缀
                .end()
            .end()
        .module
            .rule('vue') // vue-loader 相关配置
                .test(/\.vue$/) // 匹配 .vue 文件
                .use('vue-loader')
                    .loader('vue-loader')
                    .end()
                .end()
            .rule('css') // css-loader 相关配置
                .test(/\.css$/)
                .use('customer-style-loader')
                    .loader(path.resolve("./loaders/customer-style-loader.js"))
                    .end()
                .use('vue-style-loader')
                    .loader('style-loader')
                    .options({
                        injectType: "lazySingletonStyleTag"
                    })
                    .end()
                .use('css-loader')
                    .loader('css-loader')
                    .options({
                        esModule: false
                    })
                    .end()
                .end()
            .end()
        .plugin('vue-loader-plugin') // vue-loader 必须要添加 vue-loader-plugin
            .use(require('vue-loader').VueLoaderPlugin, [])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true);
    module.exports = config.toConfig();
    

    然后运行 npm run dev 命令打开浏览器看效果:

    npm run dev
    

    在这里插入图片描述

    可以看到,当我们刷新页面后,“hello” 一开始是没有样式的,然后过后 5s 后弹出 alert 点击 “确定” 后才有样式的。

    ok!style-loader 还有一些其它的功能,我就不演示了,小伙伴自己去研究哦!

    总结

    vue-style-loader 跟 style-loader 基本用法跟功能是一样的,都是往 dom 里面插入一个 style 标签去让样式生效的,但是 vue-style-loader 支持 vue 中的 ssr(服务端渲染),所以如果需要支持服务端渲染的 vue 项目,就需要用到 vue-style-loader了,如果一般的 vue 项目的话,推荐使用 style-loader,毕竟 style-loader 支持的功能还是丰富些,比如可以懒注入、可以指定位置插入标签等等。

    展开全文
  • vue中style样式动态绑定

    万次阅读 2019-08-16 10:58:41
    方法一: ... <div class="videoMa" ref="videoMa" style="width:100%;height:100%;...div id="playWnd" class="playWnd" :style="{width:videoBox.width+ 'px',height:videoBox.height+ 'px'}"&...
  • html style属性

    千次阅读 2019-05-06 15:55:26
    在html 中 style 用于为 HTML 文档定义样式信息。...style> 当做一个标签使用 下面修改自己颜色为例 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title...
  • matplotlib绘图样式(style)初探

    万次阅读 2021-01-03 10:20:45
    Styles are predefined sets ...Customizing Matplotlib with style sheets and rcParams describes the mechanism and usage of styles. The Style sheets reference gives an overview of the builtin styles. matpl
  • 列表的样式在CSS中,列表元素是一个块框,列表中的每个表项也是一个块框,只是在表项前面多了一个项目符号。列表的格式化,主要由浏览器完成,而不是由设计人员...list-style属性的语法格式为:list-style:[ list-...
  • ``` var style=ele.style; style={"borderWidth":"3px"}; style.cssText="border-width:3px"; ``` 这两种写法有区别吗
  • 迟到的推荐~两个用StyleGAN做应用的论文: 1.StyleGAN-Embedder:   这篇paper主要关于如何用StyleGAN做图像编码,是目前对我帮助非常深的一篇论文。     Arxiv地址:https://arxiv.org/pdf/1904.03189.pdf  ...
  • qTip Style

    千次阅读 2012-07-28 09:57:25
    Style 这个style对象允许你分配自定义样式给主要的qTip元素,和ThemeRoller tip选项,当使用tips plugin的时候: classes:"" 概述: 添加样式的时候使用空格隔开字符串来包含多个样式名称,应该添加给主要的qTip元素...
  • 关于vue模板的stylestyle的scoped属性

    千次阅读 2019-08-05 11:39:14
    vue模板有三部分组成,template, script, style 1,如果模板中有style部分,vue在编译过程中,会将该部分样式按照特定的样式规范编译后以style标签插入header,如图: 说明:如果style里面并没有样式,是空的,...
  • js设置style样式

    万次阅读 2019-08-13 14:28:40
    删除属性:obj.style.属性名 = ""; 读取属性:属性 = obj.style.属性名; 设置属性:obj.style.属性名 = “属性值”;
  • .style与.style.cssText

    千次阅读 2018-11-05 11:41:30
    和innerHTML一样,cssText很快捷且所有浏览器都支持。此外当批量操作样式时,cssText只需一次reflow,提高了页面渲染性能。 但cssText也有个缺点,会覆盖之前的样式。...而用style.top="80px !...
  • android studio中style.xml的使用

    千次阅读 2016-11-21 14:10:35
    style
  • 完整StyleGAN笔记:http://www.gwylab.com/pdf/Note_StyleGAN.pdf 基于StyleGAN的一个好玩的网站:www.seeprettyface.com ————————————————————...  StyleGAN的损失函数写在training/loss.p...
  • MapboxMap 之设置 Style

    千次阅读 2020-07-27 13:19:52
    Style.MAPBOX_STREETS : 完整的底图Style.OUTDOORS : 适合户外活动的通用样式Style.LIGHT : 数据可视化的微妙灯光背景Style.DARK : 用于数据可视化的细微深色背景Style.SATELLITE : 美丽的全球卫星和航空影像图层...
  • StyleGAN2 解释

    千次阅读 2020-10-21 15:10:39
    的说法, 此博客讨论的是StyleGAN2的诸如weight demodulation, path length regularization和去掉progressive growing等信息。虽然我去年底自己复现过StyleGAN2的pytorch版, 但对这些内容也有些忘记了,借此机会复习...
  • html中list-style-type与list-style的区别

    千次阅读 2019-07-08 08:45:43
    list-style与list-style-type的区别 list-stye指的是列表,是一个复合属性,list-style-type只是其中的一项。 list-style-type:设置列表项标记的类型,none表示前面没有标记,如点。 list-style-position:设置在...
  • 这里可以看到headStyle 和 bodyStyle 的类型都是object,但是为它赋值的需要注意一些问题。 如果只设置一个样式,可以直接在行内写 <a-card title="title" :bordered=false :headStyle="...
  • smartform style 设置

    千次阅读 2018-10-09 13:50:59
    使用TCODE SMARTSTYLES 进入到style的设置界面,也可以直接从TCODE smartforms 里面进入。 STYLE 分为三部分,header data, paragraph format, character format。 header data 设置style 的默认值, paragraph...
  • The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.  错误提示如上,是因为用JSX的时候,不允许在style...
  • style标签中,vue项目引入style文件,外部css文件一、css是什么?二、使用步骤1.使用style标签引入2.在style标签内使用@import导入总结 一、css是什么? CSS (层叠样式表) 层叠样式表(英文全称:Cascading ...
  • HTML 样式style

    千次阅读 2019-03-14 15:49:29
    一、HTML中的style属性:提供了一种改变所有HTML的...body style="background-color:yellow"&gt; &lt;h2 style="background-color:red"&gt;This is a heading&lt;/h2&gt...
  • <h1 style="color: red;">标题一</h1>

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 451,628
精华内容 180,651
关键字:

style