1 自我介绍
略。。。
2 vue组件通信怎么使用双向数据流通信,尽可能不用emit把方法暴露出去
文档:https://v2.cn.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A5%B0%E7%AC%A6
2.3.0+ 新增
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。
这也是为什么我们推荐以 update:myPropName
的模式触发事件取而代之。举个例子,在一个包含 title
prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:
this.$emit('update:title', newTitle)
|
然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:
<text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event" ></text-document>
|
为了方便起见,我们为这种模式提供一个缩写,即 .sync
修饰符:
<text-document v-bind:title.sync="doc.title"></text-document>
|
注意带有 .sync
修饰符的 v-bind
不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’”
是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model
。
当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync
修饰符和 v-bind
配合使用:
<text-document v-bind.sync="doc"></text-document>
|
这样会把 doc
对象中的每一个 property (如 title
) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on
监听器。
将 v-bind.sync
用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”
,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。
3 vue父子组件v-model传值
文档:https://v2.cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model
通常子组件某个变量更新,并需要告知父组件时,需要子组件触发事件并父组件监听该事件。
但是熟悉上面 v-model 的实现原理后,我们可以巧妙地运用这一原理(v-model 在内部使用不同的属性为不同的输入元素并抛出不同的事件)
在父组件中
<DomDialog v-model="isDomDialog"></DomDialog>
等同于如下常规写法:
<DomDialog v-bind:value="isDomDialog" v-on:input="isDomDialog=$event"></DomDialog>
或者
<DomDialog :value="isDomDialog" @input="isDomDialog=$event"></DomDialog>
在子组件中的接收与传值:
props:{
value:{type: Boolean,},
},
data(){
return {
dialogVisible:false,
}
},
watch:{
value(val){
this.dialogVisible = val
},
},
methods: {
// 关闭弹窗触发
confrim(){
this.$emit('input',false) // 通过 this.$emit() 向父组件传值
}
},
总结:
1.子组件设 value 为props属性,并且不主动改变 value 值
2.子组件通过 this.$emit('input', 'updateValue') 将 updateValue 值传给父组件
3.父组件通过 v-model="localValue" 绑定一个本地变量,即可实现子组件value值与父组件updateValue 值同步更新
4 keepalive 有关的生命周期
当组件在 内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。
1.activated: 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
2.deactivated: 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated
5 keepalive有几个属性 作用是什么
文档:https://v2.cn.vuejs.org/v2/api/?#keep-alive
keep-alive可以接收3个属性做为参数进行匹配对应的组件进行缓存:
- include 包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)
- exclude 排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)
- max 缓存组件的最大值(类型为字符或者数字,可以控制缓存组件的个数)
// 只缓存组件name为a和b的组件
<keep-alive include="a,b">
<component />
</keep-alive>
// 组件name为c的组件不缓存(可以保留它的状态或避免重新渲染)
<keep-alive exclude="c">
<component />
</keep-alive>
// 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存a组件
<keep-alive include="a,b" exclude="b">
<component />
</keep-alive>
// 如果缓存的组件超过了max设定的值5,那么将删除第一个缓存的组件
<keep-alive exclude="c" max="5">
<component />
</keep-alive>
配合router使用
router-view也是一个组件,如果直接被包在keepalive里面,那么所有路径匹配到的视图组件都会被缓存,用法与缓存组件相同
- 使用 include/exclude
- 使用 meta 属性
第一种方法:使用 include
//只有路径匹配到的 name 为 a 组件会被缓存
<keep-alive include="a">
<router-view></router-view>
</keep-alive>
第一种方法:使用 meta 属性
// routes 配置文件
export default [
{
path: '/',
name: 'home',
component: Home,
meta: {
keepAlive: true // 需要被缓存
}
}, {
path: '/user',
name: 'user',
component: User,
meta: {
keepAlive: false // 不需要被缓存
}
}
]
// App.vue
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
<!-- 这里组件会被缓存,比如 Home! -->
</router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive">
<!-- 这里组件不会被缓存,比如 User! -->
</router-view>
6 怎么销毁keepalive
在使用keep-alive的过程中,有时我们需要当前页面缓存,但是再某种情况下又不需要当前页面缓存,keep-alive并未提供销毁包含组件的方法,那我们可以通过手动删除cache数组中的当前页面的key值实现消除某个页面缓存的功能。
function removeKeepAliveCache () {
if (this.$vnode && this.$vnode.data.keepAlive && this.$vnode.parent) {
const tag = this.$vnode.tag;
let caches = this.$vnode.parent.componentInstance.cache;
let keys = this.$vnode.parent.componentInstance.keys;
for (let [key, cache] of Object.entries(caches)) {
if (cache.tag === tag) {
if (keys.length > 0 && keys.includes(key)) {
keys.splice(keys.indexOf(key), 1);
}
delete caches[key];
}
}
}
this.$destroy();
};
然后,在组件里的路由守卫调用removeKeepAliveCache
,同时也不需要去修改from.meta.keepAlive
了
beforeRouteLeave(to, from, next) {
if (to.name === 'selectAddr') {
// from.meta.keepAlive = true;
} else {
// from.meta.keepAlive = false;
removeKeepAliveCache.call(this);
}
next();
},
参考文献:
https://v2.cn.vuejs.org/v2/api/?#keep-alive
https://juejin.cn/post/6844903649517240328
https://segmentfault.com/a/1190000022957086?sort=votes
https://blog.csdn.net/mengweizhao/article/details/120758368
7 webpack对静态资源的处理
在我们的项目结构里,有两个静态文件的路径,分别是:src/assets
和 static/
。那这两个到底有什么区别呢?
Webpacked 资源
资源处理规则
在JavaScript里获取资源路径
computed: {
background () {
return require('./bgs/' + this.id + '.jpg')
}
}
"真实的" 静态资源
// config/index.js
module.exports = {
// ...
build: {
assetsPublicPath: '/',
assetsSubDirectory: 'static'
}
}
所有放在 static/
目录下的文件都应该是使用绝对URL/static/[filename]
引用的。如果你将assetSubDirectory
的值改成assets
, 那么这些URL就会被变成 /assets/[filename]
8 webpack的属性有哪些,有什么作用
属性 | 类型 | 作用 |
---|
entry | string、object(多入口) | 指定入口文件 |
output | object | 指定文件的出口(详细信息看下文output配置) |
mode | string | development、 production(默认, 对代码进行压缩)、none(不进行处理) |
module | object | 解析除了js、json之外的文件(详细信息查看下文module.rules 配置) |
plugins | array | 使用各种插件 eg:[new htmlWebpackPlugin()] |
devServer | object | 开发环境配置(详细配置查看下文devServe配置) |
devtool | string | 配置辅助工具(详细配置查看下文courseMap类型) |
optimization | object | 集中配置webpack优化功能(详细配置查看下文optimization配置) |
常用loader
- css-loder 处理css
- style-loader 生成style标签并且添加到项目中
- file-loader 处理图片、字体等资源文件
- url-loader 压缩图片、字体等资源文件并且转换成base64格式,减少请求次数
- babel-loader js转换loader (需要配置’@babel/preset-env’)
- html-loader 对html文件进行处理(默认会处理img src属性)
常用plugin
- clean-webpack-plugin 自动清除输出目录
- html-webpack-plugin 自动生成html文件
- copy-webpack-plugin 拷贝不需要处理的文件, 指定输出目录([‘public’])
- mini-css-extract-plugin 实现css的按需加载(样式文件不是很大建议不要单独提取150kb)
- optimize-css-assets-webpack-plugin 压缩css文件
常用插件
webpack-dev-server 提供了一个简单的web服务器,能够热更新当前项目
output配置
属性 | 类型 | 作用 |
---|
filename | string | 指定文件名称 |
path | string | 指定输入文件目录(path.join(__dirname, ‘dist’)) |
publicPath | string | 指定根目录(‘dist/’), 一般不需要指定,可以自动引入 |
module.rules 配置
属性 | 类型 | 作用 |
---|
test | 正则表达式 | 判断文件类型 |
use | string、array、object | 处理不同文件的loader,loader为数组时执行顺序从后往前执行(类型为object详细信息查看下文use配置) |
use配置(Object)
属性 | 类型 | 作用 |
---|
loader | string | 文件转换 |
option | array | 基础配置 |
eg: 图片、字体等资源处理,小于10KB 进行base64转换并且嵌入到页面中, 大于10KB不进行压缩
devServe 配置
属性 | 类型 | 作用 |
---|
contentBase | string | 为开发服务器指定查找资源目录 |
port | number | 端口 |
proxy | object | 配置代理 |
hot | boolean | 是否开启热更新(需要在plugin中调用 new webpack.HotModuleReplacementPlugin()) |
hotOnly | boolean | 当页面出现错误时不会执行热更新 |
courseMap类型
属性 | 类型 | 是否生成对应的sourceMap文件 | 是否源代码 | 特点 |
---|
evel | string | no | no | 使用evel函数包装 |
evel-source-map | string | yes | no | 能定位到行列信息 |
cheap-evel-source-map | string | yes | no | 只能定位到行 |
cheap-module-evel-source-map | string | yes | yes | 能定位到源码错误位置 |
inline-source-map | string | yes | no | 嵌入到url中 |
hidden-source-map | string | yes | no | 影藏sourceMap文件 |
nosource-source-map | string | yes | no | 看不到代码信息 |
建议:
开发环境:cheap-module-eval-source-map(会显示出源码错误位置)
生成坏境: nosource-source-map(不会暴漏源码,只会抛出错误位置)
optimization配置
属性 | 类型 | 作用 |
---|
usedExports | boolean | 标记未使用代码 |
minimize | boolean、array(自定义压缩插件) | 去除无用代码 |
concatenateModules | boolean | 尽可能将所有的模块放到同一个函数中 |
sideEffects | boolean | 判断是否有副作用 |
splitChunks | object | 设置spllitChunks.chunks = all提取公共模块 |
html-webpack-plugin 属性配置
属性 | 类型 | 作用 |
---|
title | string | html文件标题 |
meta | object | 指定窗口大小 |
template | string | 指定模板路径 |
filename | string | 指定文件名称(默认index.html) |
// webpack.config.js中配置
// npm install html-webpack-plugin --save-dev
const htmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new htmlWebpackPlugin({
title: 'cache',
meta: {
viewport: 'width-device-width'
},
template: './src/index.html'
})
]
9 webpack中loader和plugin的区别
不同的作用:
Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果
loader比较单一就是用来加载文件
不同的用法:
Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入
10 require和import的区别
无论是require 还是 import 都是不同规范下导入模块的方法,主要有以下的区别:
1、require对应导出的方法是module.exports,
import对应的方法是export default/export
2、require 是CommonJs的语法
import 是 ES6 的语法标准。
3、require是运行运行时加载模块里的所有方法(动态加载),
import 是编译的时候调用(静态加载),不管在哪里引用都会提升到代码顶部。
4、require 是CommonJs的语法,引入的是的是整个模块里面的对象,
import 可以按需引入模块里面的对象
5、require 导出是值的拷贝,
import 导出的是值的引用
参考资料:https://zhuanlan.zhihu.com/p/121770261
11 vue怎么给对象添加属性
vue.$set()
文档:https://v2.cn.vuejs.org/v2/api/?#vm-set
在开发过程中,经常遇到这样的情况:当data里边已经声明或赋值过对象或者数组(数组里边的值是对象)时,再向对象中添加新的属性,如果更新此属性的值,是不会更新视图的。根据官方文档定义:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。
当你把一个普通的js对象传入Vue实例作为data选项,vue将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter。
受现代js的限制,vue不能检测到对象属性的添加或删除。由于Vue会在初始化实例时对属性执行getter/setter转化过程,所以属性必须在data对象上存在才能让vue转换它,这样才能让它是响应的。
比如:
data () {
return {
student: {
name: '',
age: ''
}
}
},
mounted () {
this.student.age = 24
}
众所周知,直接给student赋值操作,虽然可以新增属性,但是不会触发视图( 页面 )
更新原因是:vue.js的属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。
解决方法
vue.$set(obj,key,value)
mounted () {
this.$set(this.student,"age", 24)
}
第一个参数:改变的对象
第二个参数:改变的对象中的属性
第三个参数:改变的属性值
评论区