Vue组件化

组件

组件是实现应用中局部功能的代码(HTML,CSS,JS)和资源(图片,声音,视频)的集合,凡是采用组件方式开发的应用都可以称为组件化应用

模块是指将一个大的js文件按照模块化拆分规则进行拆分成的每个js文件, 凡是采用模块方式开发的应用都可以称为模块化应用(组件包括模块)

传统方式开发的一个网页通常包括三部分: 结构(HTML)、样式(CSS)、交互(JavaScript)

  • 关系纵横交织复杂,牵一发动全身不利于维护
  • 代码复用率不高., 页面中复用的代码需要通过复制的方式在其他页面中使用

Vue组件化_第1张图片

组件化方式开发的应用

  • 每一个组件都有独立的js,css以及HTML片段,这些独立的代码只供当前组件使用,不存在纵横交错问题便于维护
  • 代码复用性增强, 页面中复用的代码通过引入组件的方式在其他页面中使用

Vue组件化_第2张图片

组件的创建、注册和使用

创建组件调用Vue.extend({该配置项和new Vue的配置项几乎相同只是略有差别})

  • 配置项中不能使用el配置项配置模板语句而是使用template配置项(组件具有通用性,不特定为某个容器服务而是为所有容器服务)
  • 配置项中的data不能使用对象的形式(数据是共享的只有一份),必须使用函数形式返回一个对象(组件的数据是独立的不能共享)
  • 配置项中的name是设置Vue开发者工具中显示的组件的名字不是设置组件的名字(默认都是驼峰式显示)
  • 创建组件的简写形式:省略Vue.extend()直接写{配置项},底层在注册组件的时候还是会调用Vue.extend()静态方法

注册组件进行管理

  • 局部注册(只能在父组件绑定的容器中或模板语句中使用):在创建Vue实例时的配置项当中使用components配置项, components:{组件的名字:组件对象}
  • 全局注册(可以在所有父组件绑定的容器中或模板语句中使用):Vue.component('组件的名字(标签名)', 组件对象)

在容器中中以HTML标签的方式使用组件

  • 使用组件时可以使用自闭合标签,但是如果不在脚手架环境中使用这种方式除了第一个元素渲染后续元素都不会渲染

组件的名字规范(不可以是HTML内置的标签名)

  • 第一种:全部小写
  • 第二种:首字母大写,后面都是小写
  • 第三种:kebab-case串式命名法(如user-login)
  • 第四种常用:CamelCase驼峰式命名法(UserLogin), 这种方式只允许在脚手架环境中使用
<script>
    // 创建组件实例对象(结构HTML 交互JS 样式CSS)
    const myComponent = Vue.extend({
                template : `
                
  • {{index}},{{user.name}}
`
, // 每次调用data方法都会返回一个对象,这个对象中的数据是独立的 data(){ return { users : [ {id:'001',name:'jack'}, {id:'002',name:'lucy'}, {id:'003',name:'james'} ] } } }) // 创建组件时省略Vue.extend() const myComponent = { template : `
  • {{index}},{{user.name}}
`
, data(){ return { users : [ {id:'001',name:'jack'}, {id:'002',name:'lucy'}, {id:'003',name:'james'} ] } } } // 在Vue实例中注册组件进行管理 const vm = new Vue({ el : '#app', data : { msg : '第一个组件' }, // 局部注册组件的只能在父组件绑定的容器中使用 components : { // userlist是组件的名字,myComponent组件实例对象 userlist : myComponent, } })
script> <div id="app"> <h1>{{msg}}h1> <userlist>userlist> <userlist>userlist> <userlist/> div>

全局注册的组件可以在所有父组件绑定的容器中或模板语句中使用

<body>
    
    <div id="app">
        <h1>{{msg}}h1>
        <userlogin>userlogin>
    div>
    
    <div id="app2">
        <userlogin>userlogin>
    div>

    <script>
        // 创建组件
        const userLoginComponent = {
            // template只能有一个根元素
            template : `
            

用户登录

账号:

密码:

`
, data(){ return { username : '', password : '' } }, methods: { login(){ // this是vc alert(this.username + "," + this.password) } }, } // 全局注册组件,自动调用Vue.extend()方法 Vue.component('userlogin', userLoginComponent) // Vue实例 const vm2 = new Vue({ el : '#app2' }) // Vue实例 const vm = new Vue({ el : '#app', data : { msg : '第一个组件' }, })
script> body>

组件嵌套

组件的划分粒度很重要,粒度太粗会降低组件的复用性, 为了让复用性更强Vue 的组件也支持父子组件嵌套使用

  • 子组件由父组件来管理,父组件由父组件的父组件管理, 在Vue中根组件就是Vue实例vm
  • 局部注册的子组件只能在父组件绑定的容器或者template配置项配置的模板语句中使用,一般是在哪注册在哪使用

Vue组件化_第3张图片

<body>
    <div id="root">div>
    <script>
        // 创建Y1组件
        const y1 = {
            template : `
                

Y1组件

`
} // 创建X1组件 const x1 = { template : `

X1组件

`
} // 创建Y组件 const y = { template : `

Y组件

`
, // 注册y1组件 components : {y1} } // 创建X组件 const x = { template : `

X组件

`
, // 注册x1组件 components : {x1} } // 创建app组件 const app = { template : `

App组件

`
, // 注册X组件,对象的属性名和属性值相同时可以省略属性值 components : {x,y} } // vm const vm = new Vue({ el : '#root', template : ` `, // 注册app组件 components : {app} })
script> body>

VueComponent & Vue

new Vue({})配置项中的this是Vue实例vm(构造函数中的this指向新创建的对象), Vue.extend({})配置项中的this是VueComponent实例vc

  • vm 和vc拥有大量相同的属性和函数,但二者并不相同,只能说vm上有的vc上不一定有,vc上有的vm上一定有
  • vm上有el属性而vc上没有,vc的data 必须是一个函数

Vue.extend()源码: 因为Sub是个局部变量, 所以每一次调用Vue.extend方法返回的都是一个全新的VueComponent构造函数(构造函数也是类型即对应一个对象)

  • 有了构造函数当Vue在解析组件标签时就会创建一个VueComponent实例,每个组件标签都会对应一个VueComponent实例

Vue组件化_第4张图片

<body>
    <div id="app">
        <h1>{{msg}}h1>
        <user>user>
    div>
    <script>
        // 创建组件
        const user = Vue.extend({
            template : `
            

user组件

`
, mounted(){ // this是VueComponent实例,user是一个全新的VueComponent构造函数(函数类型的对象) console.log('vc', this === user)//false } }) // Vue实例 const vm = new Vue({ el : '#app', data : { msg : 'vm与vc' }, components : { user }, mounted() { // this是Vue实例 console.log('vm', this) }, })
script> body>

回顾原型对象

XX的原型对象是一个共享的对象且只有一个,获取原型对象有两种方式

  • prototype :显示的原型属性(建议程序员使用的),可以通过函数.prototype的方式获取原型对象
  • __proto__:隐式的原型属性(不建议程序员使用的),可以通过实例.__proto__的方式获取原型对象

Vue组件化_第5张图片

// 构造函数(函数本身也是一种类型,代表User类型有一个prototype属性)
function User(){}
// 通过函数获取User的原型对象
let x = User.prototype
// 通过User构造函数可以创建实例
let a = new User()
// 通过实例获取到Vip的原型对象
let y = a.__proto__
// 获取的是同一个原型对象
console.log(x === y) // true
// 以下不是给User构造函数扩展属性而给“User的原型对象”扩展属性
User.prototype.counter = 1000

// 通过a实例可以访问到这个扩展的counter属性
// 访问原理:首先去a实例上找counter属性,如果a实例上没有counter属性的话,会沿着__proto__这个原型对象去找counter属性
console.log(a.counter)
//console.log(a.__proto__.counter)

vc可以访问Vue原型对象上的属性

VueComponent.prototype.__proto__ = Vue.prototype: 这行代码实现了Vue,vm,VueComponent,vc都共享了同一个Vue的原型对象

  • Vue原型对象上有很多属性和方法如$mount(),对于组件VueComponent来说就不需要再额外提供了,直接使用vc调用$mount()即可,代码得到了复用Vue组件化_第6张图片
<body>
    <div id="app">
        <h1>{{msg}}h1>
        <user>user>
    div>
    <script>
        // 给“Vue的原型对象”扩展一个counter属性
        Vue.prototype.counter = 1000

        // 创建组件
        const user = Vue.extend({
            template : `
            

user组件

`
, mounted(){ // 通过this也就是vc可以访问到Vue原型对象上的属性 console.log('vc.counter', this.counter) // msg是vm实例上的属性不是原型对象上的属性所以访问不了 //console.log('vc.msg', this.msg) } }) // user等价于VueComponent构造函数 console.log('user.prototype.__proto__ === Vue.prototype' , user.prototype.__proto__ === Vue.prototype)// true // Vue实例 const vm = new Vue({ el : '#app', data : { msg : 'vm与vc' }, components : { user }, mounted() { // this是Vue实例 console.log('vm', this) }, }) // vm实例可以访问 console.log('vm.counter', vm.counter) console.log('vm.counter', vm.__proto__.counter)
script> body>

单文件组件

单文件组件就是一个文件对应一个组件, 单文件组件的名字通常是xxx.vue,这个文件是Vue框架规定的只有它能够认识,浏览器无法直接打开运行

  • Vue框架将xxx.vue文件进行编译为浏览器能识别的 html js css的代码
  • 单文件组件的文件名命名规范和组件名的命名规范相同
  • xxx.vue文件的内容包括三块:结构HTML代码(template标签),交互JS代码(script标签),样式CSS代码(style)
  • VSCode工具可以安装vetur插件: 在编写xxx.vue文件的时候代码有高亮提示,并且也可以通过输入 生成代码
  • Auto Rename Tag插件方便同时修改标签名

export和import

export用于暴露数据,常见的暴露方式有分别暴露,统一暴漏,默认暴露

// m1.js文件中使用分别暴露属性和方法
export let school = '尚硅谷';

export function teach() {
    console.log("我们可以教给你开发技能");
}

// m2.js文件中使用对象的方式统一暴露
let school = '尚硅谷';
function findJob(){
    console.log("我们可以帮助你找工作!!");
}
export {school, findJob};

// m3.js文件中使用默认暴露(可以暴露任意类型,一般是个对象)
export default {
    school: 'ATGUIGU',
    change: function(){
        console.log("我们可以改变你!!");
    }
}	

import用于导入js文件中暴露的数据

<body>
    <script type="module">
        // 通用的导入方式,m1,m2,m3分别存储了暴露的数据
        import * as m1 from "./src/js/m1.js";
        import * as m2 from "./src/js/m2.js";
        import * as m3 from "./src/js/m3.js";
 
        // 解构赋值形式通过对象的形式使用暴露的数据,属性方法重名时使用as关键字
        // import {a, b} from ‘模块标识符'
        import {school, teach} from "./src/js/m1.js";
        import {school as guigu, findJob} from "./src/js/m2.js";
        // default是个关键字不能直接使用,需要使用别名机制
        import {default as m3} from "./src/js/m3.js";

        // 导入的简便形式但是只能针对默认暴露,m3是别名存储了暴露的数据和方法
        // import 任意名称 from ‘模块标识符’
        import m3 from "./src/js/m3.js";
        // 访问暴露的属性和方法需要加一层default结构
        console.log(m3.default.school);
    script>
body>

将所有模块的引入单独写到一个js文件中,在index,html中使用script标签直接引入这个js文件即可

//模块引入的入口文件
import * as m1 from "./m1.js";
import * as m2 from "./m2.js";
import * as m3 from "./m3.js";
 <body>
    
    <script src="./src/js/app.js" type="module">script>
body>

“组件嵌套”之单文件组件的形式

创建vm的js代码就不再写成一个组件了, 将这段js代码写到一个main.js入口文件中即可

import App from './App.vue'
new Vue({
    el : '#root',
    // 使用组件
    template : ``,
    // 注册App组件
    components : {App}
})

不管是单文件组件还是非单文件组件,永远都包括三步:创建组件、注册组件、使用组件




















剩下的HTML代码一般写到index.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.0">
    <title>单文件组件title>
head>
<body>
    <div id="root">div>
    <script src="../js/vue.js">script>
    <script src="./main.js">script>
body>
html>

组件化开发的流程: 浏览器不认识.vue文件并且也不认识 ES6 的模块化语法, 需要安装Vue脚手架

  • 第一步:浏览器打开index.html页面,加载容器
  • 第二步:加载vue.js文件,有了Vue
  • 第三步:加载main.js文件导入组件, 完成了所有组件以及子组件的创建和注册
  • 第四步:创建Vue实例vm,编译App.vue(以此类推)中的模板语句然后渲染页面

使用脚手架组件开发

安装Node.js

第一步: Node.js 的下载地址

Vue组件化_第7张图片

第二步: 一路点击下一步,添加命令到PATH环境变量,剩下按照默认选项安装即可

Vue组件化_第8张图片

第三步: 打开dos命令窗口,输入 npm -version查看npm的版本号

第四步: 配置npm镜像npm config set registry https://registry.npm.taobao.org, 执行npm config get registry返回成功即表示设置成功

Vue组件化_第9张图片

调用管理员界面,查看nodejs安装版本:输入node -v命令 ,以及查看npm版本:输入npm -v命令;

安装Vue CLI(脚手架)

Vue 的脚手架(Command Line Interface)是Vue官方提供的标准化开发平台,为我们Vue的开发提供了一条龙服务

  • Vue CLI 4.x需要Node.js v8.9及以上版本(推荐v10以上)

第一步:执行npm install -g @vue/cli命令安装脚手架(全局方式:表示只需要做一次即可)

  • 安装完成后,重新打开 DOS 命令窗口,输入 vue 命令可用表示成功了

第二步:选择一个目录使用Vue2的方式创建项目vue_provue creat vue_pro, 项目中自带脚手架环境(内置了 webpack loader),自带一个 HelloWorld 案例

  • babel:负责将ES6语法转换成ES5
  • eslint:负责语法检查

Vue组件化_第10张图片

Vue组件化_第11张图片

第三步:在创建的项目根目录下vue_pro执行 npm run serve命令编译Vue程序自动生成html css js代码放入内置服务器并自动启动服务(ctrl + c 停止服务)

  • 打开浏览器访问http://localhost:8080

Vue组件化_第12张图片

认识脚手架项目结构

Vue组件化_第13张图片

yarn

更改全局模块安装路径和缓存cache的路径

(1)、打开nodejs安装目录,在里面创建node_global和node_cache两个文件夹
配置全局安装的模块路径和缓存路径;
在nodejs根目录创建node_global,node_cache文件夹;

以管理员身份打开命令窗口,配置安装路径以及缓存路径,分别执行以下命令即可;
npm config set prefix "D:\dev\nodejs\node_global"
npm config set cache "D:\dev\nodejs\node_cache"



右键此电脑——属性——高级系统设置——高级——环境变量——系统变量,
配置环境变量,然后添加,变量值名为:NODE_PATH,变量值为npm安装路径:D:\Program Files\nodejs\node_modules;

编辑用户变量的 path,将默认的 C 盘下的  C:\Users\18280\AppData\Roaming\npm, 在path中添加:D:\Program Files\nodejs以及D:\Program Files\nodejs\node_global路径;


配置cnpm,配置淘宝镜像,默认路径下载比较缓慢,配置淘宝镜像可以加速下载速度,打开命令窗口执行以下命令即可,如果不想配置cnpm,可直接跳过此步骤;
npm install -g cnpm --registry=https://registry.npm.taobao.org
1
3.4. 直接为npm设置淘宝镜像仓库即可,命令如下:
npm config set registry https://registry.npm.taobao.org
1
以管理员打开cmd,输入npm config list 命令,查看npm的配置信息

# 临时更改为淘宝镜像源

npm --registry https://registry.npm.taobao.org install node-red-contrib-composer@latest

2、 全局使用淘宝源

 # 修改为淘宝镜像源

npm config set registry https://registry.npm.taobao.org

3、 全局使用官方源

# 修改为官方镜像源

npm config set registry http://www.npmjs.org

Vue组件化_第14张图片

npm与cnpm其实没什么大的区别,npm默认的镜像时国外的,cnpm下载镜像是国内淘宝团队的,下载速度快点,其实直接将npm的下载仓库直接设置为淘宝镜像就可以了。
不同的是在项目中下载项目依赖时包时命令不同,用npm执行npm install -g ,用cnpm时,用cnpm install -g 命令就可以了

# 安装cnpm
npm install -g cnpm -registry=https://registry.npm.taobao.org



4、安装yarn ,使用npm命令,以管理员打开命令窗口输入:npm install yarn -g命令进行安装,安装完成后,
配置yarn的执行路径;在path中添加。D:\dev\nodejs\node_global\node_modules\yarn\bin
# 全局安装命令
npm install -g yarn
或
cnpm install -g yarn

打开命令窗口,输入yarn -v即可查看yarn 版本;

使用yarn config list命令即可看到node配置的全局路径、缓存路径、以及淘宝镜像路径,查看是否安装正确;

2、更改模块及缓存存储目录

同样先在yarn的安装目录下创建yarn_global和yarn_cache文件夹,并打开命令窗口执行以下命令。

# 全局安装目录
yarn config set global-folder D:\dev\nodejs\node_global\node_modules\yarn\yarn_global
# 缓存目录
yarn config set cache-folder D:\dev\nodejs\node_global\node_modules\yarn\yarn_cache

# 查看当前源
yarn config get registry

# 修改为淘宝镜像源
yarn config set registry https://registry.npm.taobao.org

# 修改为官方镜像源

yarn config set registry https://registry.yarnpkg.com

Vue组件化_第15张图片

分析index.html

index.html文件只有一个容器,并且没有看到引入vue.js文件和main.js文件

  • Vue脚手架会自动找到main.js文件不需要你手动引入(main.js文件的名字和位置都不要随便修改)
DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    
    <title><%= htmlWebpackPlugin.options.title %>title>
    <title>欢迎使用本系统title>
  head>
  <body>
    
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
    noscript>
    
    <div id="app">div>
    
  body>
html>

配置文件vue.config.js

分析脚手架默认配置文件vue.config.js,具体配置项可以参考 Vue CLI 官网手册

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  // 保存时是否进行语法检查(如组件的名字应该由多单词组成), 默认值true表示检查,false表示不检查
  lintOnSave : false,
  // 配置入口文件的位置和名称
  pages: {
    index: {
      entry: 'src/main.js',
    }
  },

main.js

编译template配置项的模板语句报错原因: Vue包含两部分, 一部分是Vue的核心,一部分是模板编译器(占整个vue.js文件体积的三分之一)

  • 程序员最终使用webpack进行打包的时候代码肯定是已经编译好了, 这时候Vue中的模板编译器就没有存在的必要了
  • 为了缩小体积Vue脚手架中默认直接引入的就是一个缺失模板编译器的vue.js文件(Vue的仅运行时版本)
  • 注意: template的标签中的内容可以正常编译(因为package.json 文件中进行了配置)

Vue组件化_第16张图片

解决main.js文件中的无法编译template配置项的方式

  • 第一种方式引入一个完整的vue.js: import Vue from ‘vue/dist/vue.js’
  • 第二种方式使用render函数代替template配置项: 这个函数由vue自动调用,并且传递过来一个函数createElemen可以用来创建元素(创建完必须返回)
// 这里默认引入的是dist/vue.runtime.esm.js(esm版本是ES6模块化版本)
import Vue from 'vue'
// 导入App组件(根组件)
import App from './App.vue'

// 关闭生产提示信息
Vue.config.productionTip = false

// 创建Vue实例
new Vue({
  el : '#app',
  // 完整写法
  render(createElement){ 
    // 创建了一个div元素
    //return createElement('div', 'render函数')
    return createElement(App)
  } 
	
  // 箭头函数的简写形式,参数只有一个省略括号,函数体只有一条语句可以省略{}和retuen
  render : h => h(App)
  
})

App根组件和其他组件






props配置项以及获取子组件

发送组件通过组件标签的属性=""的形式传递数据, 接收组件使用props配置项可以接收其他组件传过来的数据,让组件的数据变为动态数据

  • 简单接收: props : [‘name’,’age’,’sex’]
  • 接收时添加类型限制: props : {name : Stringage : Number}
  • 接收时添加类型限制,必要性限制,默认值: props : {name : {type : Number, required : true}, age : {type : Number, default : 10}}
  • props接收到的数据不能修改(页面会刷新但控制台报错), 一般通过间接修改一个中间变量的值避免父组件重新渲染时子组件修改后的值被覆盖的问题

在App这个父组件当中先找到子组件Car,然后给Car这个子组件通过属性的形式传数据

  • 先在组件标签上使用ref属性进行标识,然后在程序中使用$refs来获取所有子组件, 然后通过标识获取具体的某一个组件
  • 获取子组件时支持嵌套的形式即this.$refs.组件标识.$refs.name表示访问子组件的子组件属性
  • ref也可以使用在普通的HTML标签上,这样使用$refs获取的就是这个 DOM 元素



子组件Car接收父组件传递过来的数据




mixins配置项(混入)

Vip.vue和User.vue代码中都有相同的methods,为了复用可以使用mixins配置进行混入(混入时配置项没有限制, 之前所学的配置项都可以混入)

  • 第一步: 提取相同的配置项并单独定义到一个mixin.js文件(一般和main.js在同级目录)
  • 第二步: 引入并在mixins配置中使用

混入时的配置项冲突问题

  • 对于普通的配置项采取就近原则即只执行组件自身的配置不会执行混入的配置(混入的意思就是不破坏)
  • 对于生命周期周期钩子函数来说,混入时会采用叠加方式先执行混入的再执行自己的

混入的方式分为局部导入混入和全局混入两种

export const mix1 = {
    methods: {
        printInfo(){
           console.log(this.name, ',' , this.age) 
        }
    }
}

export const mix2 = {
    methods: {
        a(){
            console.log('mixin.js a.....')
        }
    },
}

export const mix3 = {
    mounted() {
        console.log('mixin.js mounted...')
    }
}






全局混入在所有的组件中(包括根组件root即vm)都自动导入混入的配置项

// 等同于引入vue.js文件
import Vue from 'vue'
// 导入App组件(根组件)
import App from './App.vue'

// 导入mixin配置项
import {mix1} from './mixin.js'
import {mix2} from './mixin.js'
import {mix3} from './mixin.js'

// 全局混入
Vue.mixin(mix1)
Vue.mixin(mix2)
Vue.mixin(mix3)

// 关闭生产提示信息
Vue.config.productionTip = false

// 创建Vue实例
new Vue({
  el : '#app',
  render : h => h(App)
})

plugins 配置(插件)

插件给用来Vue做功能增强的(可插拔), 插件一般都放到一个plugins.js文件中(一般和main.js在同级目录)

  • 插件是一个对象,对象中必须有install方法并且会被自动调用,一个插件一般对应一个独立的功能
  • 使用插件分为三步: 定义插件对象并暴露,导入插件,使用插件( 通常放在创建Vue实例之前)

插件对象的install方法有两个参数

  • 第一个参数:Vue构造函数
  • 第二个参数:用户在使用这个插件时传过来的数据,参数个数无限制

定义一个插件功能是给Vue的原型对象扩展一个counter属性(通过vm和vc都可以访问)

export const p1 = {
    install(Vue, a, b, c, d){
        console.log('这个插件正在显示一个可爱的封面')
        console.log(Vue)
        console.log(a,b,c,d)
        // 获取Vue的原型对象,给Vue的原型对象扩展一个counter属性,通过vm和vc都可以访问
        Vue.prototype.counter = 1000
    }
}
// 等同于引入vue.js文件
import Vue from 'vue'
// 导入App组件(根组件)
import App from './App.vue'

// 导入插件
import {p1} from './plugins.js'
// 插上插件(删除就是拔下插件),通常放在创建Vue实例之前
Vue.use(p1, 1,2,3,4)

// 关闭生产提示信息
Vue.config.productionTip = false

// 创建Vue实例
new Vue({
  el : '#app',
  render : h => h(App)
  
})



局部样式 scoped

默认情况下vue所有组件中定义的样式最终会汇总到一块,如果样式名一致会导致冲突,此时以后来加载的样式为准(就近原则)

  • vue组件的style样式支持多种样式语言(如css、less、sass), 使用less语法需要安装less-loader:npm i less-loader
  • App根组件中的样式style希望采用全局的方式不建议添加scoped属性,子组件的样式style一般添加scoped属性

由于样式冲突那么User组件的样式会覆盖掉Vip组件的样式

  • 给style加入scoped属性后,Vue底层会给标签加上属性,这样即使样式汇到一块也不会发生冲突了















你可能感兴趣的:(Vue,vue.js,前端,javascript)