03)组件化
(01)什么时候使用组件
把组件当做自定义元素来使用
组件中的data必须是一个函数
组件是可复用的vue实例
Vue.component("组件名",{}) 定义全局组件,全局都可使用
components:{组件名:{}} 定义局部组件,只能在当前vue组件内使用
(02)单文件组件
文件拓展名为.vue
组件模板:逻辑和样式放在一起,直观易维护
template 模板 template 在vue中不会被渲染
script js逻辑
style 样式
(03)vue样式的私有化
vue的样式私有化,是给stype标签加上 scoped 就可以实现私有化
实现原理 给样式加上随机的data-v属性
(04)props类型的定义和验证
props:[
属性:{
type:[string,number] | number , 可定义两种或者一种类型 为什么要定义两种类型,因为传入的值可能因为操作等原因变为字符串或者数字,所以要定义两种类型
default:{return {} | [] }, 默认值,对象或者函数必须从一个工厂函数中获取
require:true, 是否必传
validator(val){ 自定义验证函数,如果不传值就不会被调用,所以结合required一起使用
return 布尔值
}
}
]
(05)插槽的使用
插槽分为匿名插槽和具名插槽,这里只讲解匿名插槽
定义插槽:
<slot name="插槽名字" >
</slot>
使用插槽:
<template slot="名字">
</template>
(06)vue组件的通信父子,子父,兄弟
父子通信:
props:
定义:<父组件 :属性="值" />
使用:子组件 props:["属性"] 直接使用属性名就可
需要注意:props传过来的值,只可使用,不可直接修改,可以深度克隆赋值给变量之后再修改
$refs,$children:
定义: <父级组件 ref="名字" />
使用:this.$refs[名字] 这样就可获取到子组件的实例,就可直接修改里边的属性
定义: 无须定义
使用:父级里边使用 this.$children 获取到所有子组件,然后查找修改
子父通信:
$parent,$root
定义:无须定义
使用:this.$parent 这样就可获取到父组件的实例,然后修改属性,调用方法等。
定义:无须定义
使用:this.$root 这样就可获取到根(root)的实例,然后修改属性,调用方法等。
$emit
定义: this.$emit("事件名",数据) 子组件
使用: <父组件 @事件名="事件名" /> 然后就可以接收到
$slot-scope 作用域插槽
定义: <slot :属性="值" :属性="值" ></slot>
使用: <父组件>
<template slot-scope="对象名">
<span>{{对象名.属性}}</span>
</template>
</父组件>
兄弟通信:
window.eventBus
定义:window.eventBus=new Vue()
使用:
需要发送值:window.eventBus.$emit("事件名",参数)
需要接收值:window.eventBus.$on("事件名",(参数)=>{}) 在钩子函数中定义,不然接收不到
(04)vuex vue中的状态管理
解决的问题?
① 多层嵌套组件,兄弟组件之间传参繁琐易错
② 同一根数据在不同的组件中都有使用,修改,或者拷贝,不易维护,会产生冲突
vuex是什么?
① 抽取组件的状态,全局统一管理
② 组件数构成了一个巨大的View,不管在树的那个位置,任何组件都能获取状态(读取状态)或者触发行为(变更数据)
③通过强制规则维护视图和状态之间的独立性
介绍:
state 数据存放的地方,不可直接更新state的数据,需要调用方法来更新数据
getters 获取数据,相当于computed,数据也可从state里边直接获取
mutations 更新数据,只可以执行同步的任务,异步任务要放在actiosn里边来实现
actions 派发更新数据的事件,可以执行异步的任务,可同时派发多个commit事件,或者dispatch派发actions事件
modules 模块化,数据的模块化,可以定义子模块来管理数据
使用:
state:{
数据:值
}
getters:{
自定义函数名(state,val){
return
}
}
mutations:{
自定义函数名(state,val){
state.属性名=val
}
}
actions:{
事件名({commit,state,getters},val){
commit("mutations的事件名",val)
}
}
modules:{
名字:{
namespsced:true, //开启私有化
}
}
modules的使用
未开启私有化的情况
他的action、mutation 和 getter都是挂载在全局的vuex上的,修改的时候,会
同时触发两个事件,触发全局的和模块的
开启私有化的情况
rootState 和 rootGetters
会作为第三第四两个参数传给getters,赋值给actions的第一个参数对象中
全局命名空间内分发 action 或提交 mutation,{ root: true } 作为第三参数传给 dispatch 或 commit 即可
(05)vue动画
reverse 规定动画反向播放
什么时候用?
元素组件进入,离开视图时
(1) 条件渲染 v-if
(2) 条件展示 v-show
(3) 动态组件, 加给组件根节点,用transition做组件根节点
实现原理?
vue会在恰当的时机,添加/删除类名
类名的含义
(1)v-enter ——> 定义离开的结束状态 <—— (6)v-leave-to
(2)v-enter-active ——> 进入过渡中,定义过渡时间和曲线 <—— (5)v-leave-active
(3)v-enter-to ——> 进入结束,离开开始,与自身元素样式一致 <—— (4)v-leave
v: 类名的默认前戳, 如果transition定义了name属性,那么name就会取代v
自定义类名:定义在transition上 会覆盖默认的过渡类名
状态-class 例如:enter-class="" enter-active="类名"
缺陷:
如果两个相同的标签都在transition的包裹中,并且样式差不多,都是动态的额,那么vue会复用元素,如果想让重新添加的话,必须加一个第一无二的key,两个key不同
(06)vue的面试题
(01)动态绑定图片
import 变量 from 图片路径
require("路径")
在循环中 调用方法 getImage(路径){ return require(路径)}
(02)v-for和v-if的区别
写在一个标签上的时候,v-if的优先级高于v-for,也就是说,v-if会执行在每次循环中
(03)组件name属性的作用
1.当项目使用keep-alive时,可搭配组件name进行缓存过滤
2.vue-devtools调试工具中如果定义了name就显示的是name名,没有定义name就显示的是组件名
(03)如何深度监听路由
$route:{
}
(04)打包上线之后代理不起作用
打包,前端进行打包,后端进行上线
单页面应用,就生成了一个页面
把dist文件夹给后端,后端进行上线
如果没有看到页面
publicPath:"./" 2.0 要修改静态资源的位置,才能正确显示页面
(05)vue怎么创建多页面应用
1. 首先配置vue.config.js
const glob = require("glob");
function getEntry(url) {
let entrys = {};
glob.sync(url).forEach((item) => {
// splice(-3)取数组后三项
let urlArr = item.split("/").splice(-3);
entrys[urlArr[1]] = {
entry: "src/pages/" + urlArr[1] + "/" + "main.js",
template: "src/pages/" + urlArr[1] + "/" + "index.html",
filename: urlArr[1] + ".html",
// title: "pages-" + urlArr[1],
};
});
return entrys;
}
let pages = getEntry("./src/pages/**?/*.html");
module.exports = {
pages,
devServer: {
open: true, // npm run serve 自动打开浏览器
index: "index.html", // 默认启动页面
},
productionSourceMap: false,
};
2.然后创建每个页面的目录
views 里边放置模板
app.vue 主文件
index.html 模板文件
index.js store的文件
main.js 主文件
router.js 路由的主文件
3. 更改每个
(06)vue组件的钩子函数和路由的钩子函数执行顺序
进入顺序: beforeEach ——> beforeEnter ——> beforeRouteEnter ——> afterEach ——> beforeCeated ——> created ——> beforeupdate ——> updated ——> beforeMount
出去顺序:beforeRouteLeave ——> beforeEach ——> beforeEnter ——> beforeRouteEnter ——> afterEach ——> beforeCeated ——> created ——> beforeupdate ——> updated ——> beforeMount
(07)keep-alive与生命周期的执行顺序
进入顺序:beforeCreated ——> created ——> beforeupdate ——> updated ——> beforeMount ——> mounted ——> activated
出去顺序:deactivated ——> beforeCreated ——> created ——> beforeupdate ——> updated ——> beforeMount ——> mounted
(08)MVVM的优缺点 vue的优缺点
优点:数据驱动视图,组件化开发,没有页面之间的切换,不会出现白屏现象
缺点: 1.首次加载耗时比较多;
2.不利于SEO
3.不可以用导航实现前进后退效果;
4.页面复杂度高
(09)为什么组件的data在vue.js在是一个对象 在组件中用的是函数返回的
当一个组件被定义,data必须声明为返回一个初始数据对象的函数,因为组件课程被用来创建多个实例,如果data仍然是一个纯粹的对象,则所有的实例将共享医用同一个数据对象,通过提供data函数,每次创建一个新的实例之后,我们能够调用data函数,从而返回初始数据的一个全新的副本数据对象
因为组件要复用,所以要返回一个深度克隆的data数据,不然两个数据会共享,也就是App这个组件不用加,因为是根组件
(10)如何为对象添加属性,删除属性,至少写书3种方法
添加:
this.$set(对象名,属性名,值) 全局添加 Vue.$set(data,属性名,值)
this.对象名.属性名=值
this.对象名[属性]=值
Object.assign(对象1,对象2)
Reflect.set(对象名,属性名,值)
删除:
Reflect.deleteProperty(对象名,属性名)
this.$delete(对象名,属性名,值) 全局添加 Vue.$delete(data,属性名,值)
delete 对象名.属性名
delete 对象名[属性名]
#### (11)vue封装组件的原则和封装组件时需要注意的点
高内聚,低耦合,复用性
封装组件时需要注意的点:
不能和html标签名重名,只能有一个根标签
(12)父组件用props传过来的值,子组件怎么接收
props:[
obj:{
default:()=>{}, 必须是一个数组或者对象
require:true,
type:Array
}
]
作用域的问题,防止变量的污染