生命周期
// 创建之前,在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化,不能访问data数据
1. beforeCreate(){
console.log('beforeCreate',this.msg);
},
//创建之后,data和methods中的数据已经初始化,此时可以访问data数据
// 一般在这个函数中发起ajax请求
2. created(){
console.log('created',this.msg);
},
// 挂载之前,表示模板已经在内存中编译完成,但尚未把模板渲染到页面中。
// 此时还没有渲染用数据生成的新dom
3. beforeMount(){
console.log('beforeMount',this.el);
},
// 更新之前,当且仅当data被修改时才触发这个生命周期函数,但此时仅仅是数据被修改,页面还未更新。
5. beforeUpdate(){
console.log('beforeUpdate',this.msg);
console.log('beforeUpdate',this.el.innerHTML);
},
// 销毁之前,当执行beforeDestory钩子函数的时候,Vue实例就已经从运行阶段,进入到了销毁阶段。
// 当执行beforeDestory的时候,实例身上所有的data和所有的methods,以及过滤器、指令...都处于可用状态,此时还没有真正执行销毁过程。
7. beforeDestroy(){
console.log('beforeDestroy');
},
// 销毁之后,当执行到destoryed函数的时候,组件已经被全部销毁了,data与methods均不可用。
// 更改data数据,页面不会更新
//应用: 清除定时器
8. destroyed(){
console.log('destroyed');
}
当使用了<keep-alive>缓存组件时,会增加两个生命周期钩子
Vue全家桶
vue的全家桶:
vue.js
vue-router.js
vue-cli (脚手架,快速搭建vue项目)
axios
vuex.js
v-if与v-show的区别
v-if的显示和隐藏 是dom的创建与销毁
v-show的显示和隐藏是 基于display-none 和 display-block 无论是显示或是隐藏都会生成dom
vue指令
v-html 元素的innerHTML
v-text 元素的InnerText 只能用在双标签中
v-model 双向数据流绑定 主要作用于表单的 value 属性
v-bind 给元素绑定动态属性
v-on 处理自定义原生事件
v-if
v-else
v-else-if
v-show
v-once 只渲染一次 ,数据改变,视图更新,但v-once对应的元素不会再更新
v-slot 插槽
vue 脚手架中的data为什么必须是个函数
避免组件中的数据互相影响
组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
vue中计算属性computed和方法methods和侦听器watch的区别
-
计算属性和方法都是函数,计算属性一定有返回值,它通过对数据进行处理,返回一个结果
2. 在模板中调用时,计算属性不加(),而methods必须需要加() 3. 计算属性和方法最主要的区别是计算属性有缓存功能。 方法被调用时每次都要重复执行函数 计算属性初次调用时执行函数,然后会缓存结果。当再次被调用时,如果依赖的响应式数据没有发生改变,则直接返回之前缓存的结果 。 如果依赖发生了改变,则会再次执行函数并缓存结果 4. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
watch:
1. 侦听响应式数据的变化,数据变化时,执行相应的业务逻辑,可以有返回值,也可以没有
2. 侦听器默认在页面初始化时不执行,只有侦听数据发生变化才会执行。添加上immediate可初始化时就执行
3. 添加上immediate可初始化时就执行
Vue中如何获取原生dom
- 在元素标签上添加ref属性
- 通过this.$refs.属性名来获取dom
- 应用场景: 楼层导航中,要获取每个楼层距离页面顶端的偏移值
注意:如果是异步请求的数据渲染的dom 需要使用 this.$nextTick()回调来获取更新后的dom
<ul ref="ulEl">
<li v-for="(item,index) in list" ref="liEl">{{item}}</li>
</ul>
<p ref="pEl">这是一个段落</p>
Vue中的 this.$nextTick()
一般在请求数据后,需要获取dom的时候使用。
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
Vue中 this.$router 与this.$route的区别
在一个vue组件中,都可以访问到这两个对象,它俩的区别
this.$route是路由记录对象,只读,存储了与路由相关的信息
this.$router是路由对象,用来进行路由跳转
什么是SPA 单页面应用
单页Web应用(single page web application,SPA): SPA 是一种特殊的 Web 应用,是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的。它将所有的活动局限于一个 Web 页面中,仅在该 Web 页面初始化时加载相应的 HTML 、 JavaScript 、 CSS 。一旦页面加载完成, SPA 不会因为用户的操作而进行页面的重新加载或跳转,而是利用 JavaScript 动态的变换 HTML(采用的是 div 切换显示和隐藏),从而实现UI与用户的交互。在 SPA 应用中,应用加载之后就不会再有整页刷新。相反,展示逻辑预先加载,并有赖于内容Region(区域)中的视图切换来展示内容。
实现数组,对象更新检测的方法
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
// ====================================数组更新检测
// 三个参数: 数组,索引,新值
Vue.set(this.list,3,5) //可以触发视图更新
this.$set(this.list,3,5) //可以触发视图更新
// =====================================对象的更新检测
// 三个参数:对象,属性,新值
Vue.set(this.person,"sex","男") //可以触发视图更新
this.$set(this.list,3,5) //可以触发视图更新
for循环中的key值的作用
需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
所以一句话,**key的作用主要是为了高效的更新虚拟DOM**。
另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
为什么v-for和v-if不能在同一标签(元素)上
v-for比v-if优先,即每一次都需要遍历整个数组,影响速度。
<div
v-for="(fileMsg,index) in fileMsgList"
:key="fileMsg.id"
v-if="index < 2"
>
<sys-file-layout :fileMsg="fileMsg"></sys-file-layout>
</div>
以上代码,如果有100条数据,虽然显示两条,但需要遍历100次,因为v-for优先
更好的解决方案: 是用computed先获取符合条件的数据,再进行遍历
事件修饰符
事件修饰符: @click.修饰符
1. @click.stop 阻止冒泡
2. @click.prevent 阻止浏览器默认行为
3. @click.once 只执行一次
4. @keyup.键名 (13,enter都是指回车键, 38: 上箭头)
5. @click.self 当事件发生在该元素本身而不是子元素的时候会触发;
6. @click.capture 在事件捕获阶段触发事件处理程序
7.@keyup.native 使非原生标签也可以绑定事件
token的工作流程
1.用户填写登录信息,发起请求,服务端收到请求,去验证用户名与密码
2.验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
3.客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
4.客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
5.服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
什么是Vuex
如果应用比较简单,就不需要使用Vuex,直接使用父子组件传值及它传值方式即可,使用Vuex就要额外的引入vuex的框架,可能是繁琐冗余的
如果需要构建一个中大型单页应用,就可以使用vuex更好地在组件外部管理状态
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex的工作流程
一、在项目创建store文件夹,及index.js
定义相关的vuex的state, getters actions mutations
二、在入口文件main.js中引入store,并在根实例注册
三、在任一组件中,通过this.$store.state就可以访问到共享数据
四、当通过组件要修改store中的数据时,
1. 如果该操作是同步的,可以用this.$store.commit()来触发mutations, 只有mutations才可以直接更改state共享数据
2. mutations中只能有同步操作,不能有异步操作
3. 如果修改数据的操作是异步的,通过this.$store.dispatch()触发actions, actions中可以发起异步请求,获取数据后,再调用 commit触发mutations,通过mutations修改共享数据
Vuex的五个属性
State
储存公共数据
Action
类似于mutation 不同在于
Action 提交的是mutation,而不是直接变更状态,(action不能直接更改state数据)
Action 可以包含任意异步操作
总结一下:
mutation不能有异步操作,而action可以有异步操作
mutation可以直接更改数据,而action只能通过提交mutation,通过mutation的方法来改变数据
实际通过组件改变数据时,如果没有异步操作,可以直接提交(commit)mutation,如果有异步操作,必须派发(dispatch)action,通过action提交(commit)mutation来更改数据
Mustion
更改Vuex中store中的状态唯一的办法是提交mutation
mutation的方法中有两个参数,一个是state,第二个是参数
mutations:{
方法名(state,参数){
state.属性=参数
}
}
在组件中提交mutations的方法:this.$store.commit('方法名',参数)
state中的数据时响应式的,数据改变,相关视图会重新渲染
getters
就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
Modelu 模块
Vuex中的辅助函数
mapState
mapGetters
mapActions
mapMutations
Vue中如何自定义组件
一、普通组件
- 新建一个单个文件组件 *.vue , 内部: <template> <script> <style>, 导出
- 在父组件中引入组件
- 在components配置项中进行注册
- 在模板直接使用
二、路由组件
- 新建一个单个文件组件 *.vue , 内部: <template> <script> <style>, 导出
- 在路由文件中引入组件
- 在路由配置中,设置path和对应的component选项,来配置路由
- 在路由切换时,如何匹配到当前组件所对应的路由,则会在<router-view>中渲染该组件
页面跳转的方式
1.声明式导航
<router-link to="/index"></router-link>
2.编程式导航
//在当前路由后添加路由
this.$router.push('/index')
//替换当前路由
this.$router.replace('/index')
//上一页下一页
this.$router.go(-1)
this.$router.go(1)
路由传值
1.直接在路径后写?id=1 此方法类似get请求 参数会直接写在url地址后 使用query接收
<router-link to="/index?id=1"></router-link>
this.$router.push({path:'/index?id=1'})
this.$router.push({path:'/',query:{id:1}})
接收参数
this.$route.query.id
2. 需要在路由表配置传过去的值的键名 此方法类似post请求 使用params接收 页面刷新数据不会丢失
{path: '/index/:id', component: Index}
<router-link to="/index/1"></router-link>
this.$router.push({
path: `/index/${id}`
})
this.$router.params.id
3. 使用路由的name属性来确定匹配的路由,通过params来传递参数
this.$router.push({
name: 'index',
params: {
id: id
}
})
{
path: '/index',
name: 'Index',
component: Index
}
接收
this.$route.params.id
动态路由的实现
动态路由应用场景 : 样式相同数据不同时 可以使用动态路由实现组件复用 (详情页)
-
在路由配置中,设置path选项为"/url/:属性名"
path: "/detail/:id"-
传递参数: 在url后加/加参数
<router-link to="/detail/3"></router-link>
-
在组件中接收参数的方式:
this.$route.params.属性名如果在切换动态路由组件时,每次路由组件都会销毁,则在created中接收参数,
比如: 列表进详情如果在切换动态路由组件时,每次路由组件被复用,则用watch监听路由的变化,来获取参数
比如: 美团--> 发现--->三个版块的切换: 推荐 , 丽人, 旅行, 版块切换时,组件复用,只是传参不同
-
vue中实现角色权限管理
前端的权限管理 实现方案
首先登录验证 成功返回
token --------------------------------存到本地存储
用户权限id --------------------------------存到本地存储
路由表信息 --------------------------------存到vuex(页面刷新 vuex会被重置 )--------所以也需要存到本地存储中
设置请求拦截器 添加请求头 token 和 用户权限id
后端接收到请求 首先验证 token
动态路由法
登陆后 获得到后端返回的uid(用户权限等级),或者路由表的树,然后把相对应的路由表动态添加到公共路由表中,同时在最下边配置全局路由防止用户访问无权限页面
{
path: "*",
redirect: "/login",
},
路由元信息法
在路由元信息的meta属性中添加 meta: { role: ['admin','user']}
在路由前置守卫中判断逻辑:
1 是否已经登录(有token)
2 indexOf 获取自身的用户名对比要前往的页面的role属性 中是否允许访问(不为-1) 如果允许则放行 不允许则拦截并跳转404
路由元信息+动态路由
(配置路由前置守卫,路由表分两个一个是不需要任何权限的(login),一个是需要权限的)
首先先登录获得token,和后端数据库的user_info (用户名,头像,用户权限(admin))
前端获得数据后 存到本地
此时登录成功跳转新页面时,会被路由前置守卫拦截判断 是否有token 有token的情况下判断是否有user_info,
获取到user_info中的用户权限 并使用数组的过滤方法找出有权限访问的路由的路由信息 生成一个新的数组,
然后动态添加到路由表中(每次跳转都会执行)
Vue中添加动态路由
动态添加路由的API router对象的addRoutes方法,参数必须是一个数组
// 把下面的路由配置动态添加到路由表中
let route = [{
path: '/user',
component: ()=> import("@/views/user.vue")
}]
this.$router.addRoutes(route)
alert('添加了新路由')
角色管理(权限管理)
- 在需要动态添加的路由上添加角色的路由元信息 meta: { role: ['admin','user']}
- 在用户登录后,会根据用户账号,来过滤有权限的路由,并把这些路由通过addRoutes方法动态添加到路由表中
嵌套路由
一、在路由配置中,一级路由中添加children选项,来配置嵌套路由
const routes = [
{
path: '/home',
component: ()=> import(路由组件的地址),
children: [
{
path: 'star',
component: Star
}
]
}
]
二、在父组件中,通过<router-link to="/home/star">跳转到该嵌套路由
三、该嵌套路由对应的出口 <router-view>是在它的父级路由组件中定义的
solt
slot就是子组件里给DOM留下的坑,规定父组件写在子组件标签里的内容 在哪里显示
<子组件>DOM</子组件>
slot动态的DOM、props是动态的数据
1.匿名插槽
2.具名插槽
3.作用域插槽
组件之间传值的方法
兄弟组件之间传值的方式
1 vuex
2 子传父 父传子
3 在main.js中定义一个新的vue实例并导出,在子组件1中导入该实例,使用该实例的$emit方法自定义事件并发出数据,在子组件2中监听该自定义事件,并接受该值(案例是用一个回调函数以传参的方式获取)
父子组件之间传值的方式
1 在子组件标签上自定义属性并传值,子组件内部使用props接收
2 回调函数 在父组件定义一个回调函数 this.num=2 并且把num变量和这个回调函数传给子组件,子组件接收后就可以在子组件内部调用父组件函数
3 $parent $children属性
在子组件中 this.$parent.num访问父组件的num变量
在父组件中 this.$children[0].num访问第一个子组件的num变量
在父组件中定义变量,子组件获取并使用
5 $attrs $listeners 实现父孙组件通信
6 $ref 在子组件上注册ref 之后使用$refs.子组件.属性 来获取属性和方法
MVVM 与 MVC
MVC和MVVM都是程序开发的架构模式
MVC: M,即model,指数据层 V,指view, 即视图层 C, controller,控制器
View层发起数据请求,Controller层接到请求后,接收参数,把命令传向Model层,Model层处理数据后,把数据传回controller,而controller把数据传回客户端,也就是view层
典型代表: nodejs的Egg框架, php的ThinkPHP框架都是使用的MVC模式
MVVM: M: model,数据层 V: view,视图层,即UI , VM (ViewModel)是视图层和数据层的中间层
典型代表: Vue框架
Vue的双向数据绑定就得益于MVVM框架, 视图层改变,底层封装好的VM层会更新数据,而数据改变,VM层会更新视图
双向数据绑定的原理
1.采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时发布信息给订阅者,触发相应的监听回调
2.当把一个普通的javascript对象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用Object.defineProperty 将它们转为 getter/setter
3.用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化
4.Vue3中用ES6的proxy对象替换了Object.defineProperty(),因为Object.defineProperty() 只能劫持一个属性,而proxy可以劫持对象的所有属性
路由导航守卫
一、 全局前置守卫
router.beforeEach((to,from,next)=>{})
二、 全局解析守卫
和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
router.beforeResolve((to,from,next)=>{})
三、 全局后置钩子
和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
router.afterEach((to,from)=>{})
四、 路由独享的守卫
在路由配置上直接定义 beforeEnter 守卫
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
五、 组件内的守卫
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
完整的导航守卫解析流程
- 导航被触发。
2. 在失活的组件里调用 beforeRouteLeave 守卫。
3. 调用全局的 beforeEach 守卫。
4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
5. 在路由配置里调用 beforeEnter。
6. 解析异步路由组件。
7. 在被激活的组件里调用 beforeRouteEnter。
8. 调用全局的 beforeResolve 守卫 (2.5+)。
9. 导航被确认。
10. 调用全局的 afterEach 钩子。
11. 触发 DOM 更新。
12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
路由中的滚动行为设置
应用场景 : 在一个路由组件中滚动页面,切换到另一个组件中时,滚动条自动恢复到页面顶端的位置
下面的代码要加在router对象的配置中
//创建路由对象
const router = new VueRouter({
routes,
scrollBehavior(to, from) {
return { x: 0, y: 0 }
}
})
vue虚拟DOM
第一种: 更详细
1、读取data数据
2、读取模板
3、数据 + 模板 生成虚拟DOM(虚拟DOM就是一个JS对象,用它来描述真实DOM)(损耗一点性能)
原本准备生成的真实dom: <div id=“abc”><span> hello world </span></div>
虚拟DOM:['div', {id: 'abc‘}, ['span', '', 'hello world']]
4、用虚拟DOM的结构生成真实的DOM -> 视图显示 (用createElement可基于虚拟DOM生成真实DOM)
真实DOM:<div id='abc'><span></span></div>
5、当data发生了变化
6、数据 + 模板 生成新的虚拟DOM:
['div', {id: 'abc'}, ['span', '', 'hi world']](极大提升性能)
7、比较原始虚拟DOM和新的虚拟DOM的区别,找到的区别是span中的内容发生了变化(极大提升了性能)
8、将变化的部分生成真实DOM (用createElement可基于虚拟DOM生成真实DOM)
9、将不同部分渲染在页面(直接操作DOM,改变span中的内容)
虚拟DOM优点:1、性能提升了 2、它使得跨端应用得以实现,比如:React Native
第二种: 简洁版
1.获取数据
2.根据数据创建VDOM (相当于给对象赋值)
3.根据VDOM渲染生成真实DOM ( 根据createElement(‘DIV’) )
4.当数据发生改变后,又会生成新的VDOM
- 通过 diff 算法 比对 多次生成的 VDOM, 将不同的内容比对出来,然后再进行真实DOM渲染,
一样的内容是不会进行渲染的,这就是VDOM 的 ‘就地复用’ | ‘惰性原则’
keep-alive
组件缓存
内置组件中<keep-alive>
被其包裹的组件,在v-if=false的时候,不会销毁,而是停用
v-if="true" 不会创建,而是激活
避免频繁创建组件对象的性能损耗
最重要的是前两条:
一、keep-alive组件: 缓存组件
作用:可以让组件保留状态,避免重新渲染,提升页面性能
二、举例: 在tab切换中,切换三个组件,不用keep-alive,每个组件在重新显示时,都会再执行created,并重复发起请求
如果在外面包裹keep-alive, 则初次创建后会缓存组件,再次显示,不会再执行created,而是直接显示缓存的内容,不会再重复发起请求
三、使用keep-alive后,缓存组件会多两个生命周期钩子:
当缓存组件被激活时
activated(){
console.log('a-当缓存组件被激活时');
},
当缓存组件失活时
deactivated(){
console.log('a-当缓存组件失活时');
}
四、keep-alive有两个属性: include exclude
<keep-alive include="a1"> 只有a1被缓存,a1是组件的name属性的值
<keep-alive exclude="a1"> 只有a1没有被缓存
五、实例: 参考vue资料: app各阶段项目代码-----21-0401-keep-alive缓存组件在项目中的使用(component组件-动态路由组件)
六、**** 在动态路由的出口 <router-view>上使用keep-alive的技巧
如果不用keep-alive,会重复发起请求(请求写到created,不会重复请求,但写到watch中,监听$route的变化,就会重复请求)
使用的步骤:
(1) 在动态路由组件内部的created中发起ajax请求
(2) 设置key值
<keep-alive>
<router-view :key="$route.fullPath"></router-view>
</keep-alive>
自定义过滤器
一、应用场景 :
- 展示商品价格时,添加人民币符号
- 展示时间时,把时间戳转换为规范的时间
二、 定义
全局定义
Vue.filter(”过滤器名称", (要处理的数据)=>{
return 处理后的结果
})
局部定义
new Vue({
filters: {
过滤器名称: (){
}
}
})
三、使用时
<div>{{price | 过滤器名称}}</div>
自定义指令
一、应用场景 : 初始化时,文本框获取焦点
二、 定义
全局定义
Vue.directive(”focus", (要处理的数据)=>{
return 处理后的结果
})
局部定义
new Vue({
directives: {
focus: (){
}
}
})
三、使用时
<input type="text" v-focus>
Vue中如何实现服务器代理
在vue.config.js中通过proxy代理,实现跨域
module.exports = {
......
devServer: {
// 代理
proxy: {
'/api': {
target: 'http://localhost:3000/',
changeOrigin: true,
//根据具体需求可选择把url中的/api部分替换为空
//pathRewrite: {
// '^/api': ''
//}
}
}
}
}
- 上线后,用Nginx实现服务器代理
打包vue项目
npm run build
把dist文件夹放在nginx根目录
修改nginx的 conf/nginx.conf
server {
listen 80; #nginx服务器端口
server_name localhost; #nginx域名
location / {
root dist; #首页所在文件夹
index index.html index.htm;
}
location /api/ {
proxy_pass http://127.0.0.1:3000; # 将/api/开头的url转向该域名
}
}
重载nginx,浏览
nginx -s reload
3000端口的服务器要打开
vue-router的两种路由模式
hash: 地址栏中有#
history: 地址栏没有#,更好看一些
改变模式,添加mode选项,默认是hash
const router = new VueRouter({
routes,
mode: 'history'
})
hash: 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
history: 如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
style 中的 scoped的作用
基本要求: 记住第一条
一、 scoped的作用: 使当前组件的样式不会和其它组件冲突,因为它会给每个组件相关的选择器添加不会重复的属性
h1 {
}
h1[data-e543434] {
}
二、注意事件:
1、使用 scoped 后,父组件的样式将不会渗透到子组件中。
2、不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。
3、这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式
<style scoped>
</style>
三、在swiper轮播图中,如果要修改分页器的样式,要进行样式穿透(穿透之后,父组件定义的样式可以作用于子组件中的子元素)
(因为有scoped,所以默认情况下,父组件的样式不能作用于子组件的子元素)
下面这句话放在所有选择器的上面
1. scss的样式穿透的写法: 加上/deep/
.swiper-container /deep/ .swiper-pagination-bullet {
background-color: #f00;
opacity: 1;
}
2. stylus的样式穿透的写法: 加上::v-deep
.wrapper ::v-deep .swiper-pagination-bullet
opacity 1
background-color #fff