代码中使用
- 在方法中使用 obj&&this.gjk = ‘12’ 来替代if(obj){ this.gjk = ‘12’}
- 使用template来替代div;因为v-for或者v-if、v-else这样渲染后不会多一个dom( 标签是一种 HTML5 新增的标签,主要用于在前端开发中定义可复用的组件模板或者临时存放未被渲染的 HTML 代码。它本身并不会在页面上显示任何内容,只是充当了一个容器的作用。)
el-dialog的内容是懒渲染的
Dialog 的内容是懒渲染的,即在第一次被打开之前,传入的默认 slot 不会被渲染到 DOM 上。所以就导致了 我们在el-dialog的mounted声明周期操作dom时候出现异常,比如挂载echarts图表等。因此,如果需要执行 DOM 操作,或通过 ref 获取相应组件,请在 open 事件回调中进行 (不会被渲染到 DOM 上,是在虚拟dom中吗)
图是对应的dom结构,发现确实是默认slot里的dom未渲染
el-dialog组件里以及子组件声明周期在弹框打开前执行
el-dialog 的内容是懒渲染的,但是el-dialog的组件里以及子组件的声明周期仍会执行一遍( el-dialog所在的父组件挂载完成即使visible属性为false),因为虽然 el-dialog内容dom没有挂载,但是el-dialog组件是已经挂载了的。
el-dialog 里 默认slot的组件的生命周期会执行两遍问题是由于el-dialog的懒加载问题形成的吗?
一般情况下是子组件先渲染,子组件渲染完成后,父组件完成渲染。(但是vue官方声明了在mounted不会保证子组件渲染完成,)
下图是封装的el-dialog组件被打开的时候,发现el-dialog其中的组件的mounted的生命周期又被执行了一遍。
tabs里“懒加载”
el-tabs 里el-tab-pane默认不是 懒加载的,就是说即使不选中这个pane,也会渲染出dom的。
tabs里 tab下组件和dialog默认插槽里组件会执行自己本身mounted以及子组件的mounted是一个道理的
tabs 这个类标签是可以通过 lazy属性来设置tabPane设置懒加载
vue3使用suspense来懒加载组件
<suspense>
<tabRuleDetail></tabRuleDetail>
</suspense>
vue中使用v-model为啥可以绑定一个空对象
vue中使用v-model为啥可以绑定一个空对象,即使data中该对象没有申明一个
属性
,该对象的身上的属性也是双向绑定,是响应式的
下面是v-model=ruleForm.Address
编译后
如data上可以看到该对象上的属性
下图是使用 {{}} 语法编译后的
下图是二者的对比
el-form的form的作用
以下表单指input或el-input这些,而el-form或el-form-item则会直接写明。
1、确实,在表单中有个v-model绑定后,el-form的model有没有一点都不影响,你可以删除不写。
2、目前el-form的model主要用表单验证的,也就是配合el-form的rules和el-form-item的prop来使用的。不信的话,你可以增加一个rules和prop(为了调用验证方法,也el-form也加一个ref属性,相当于id或者class选择器的意思),但是不写model,然后验证的话,会提示缺少model,导致无法验证成功。
所以el-form的model干嘛用的?目前看来主要是为了配合表单验证。里面的逻辑大概是,在el-form-item上写一个prop,这个prop左手对应着数据源(即用model.prop找到对应的数据源所以只要model这个对象身上有对应prop的属性就行。
),右手对应着验证规则(即用rules.prop找到对应的规则)。然后就快乐地验证去了。
至于为什么不能将el-form的model+el-form-tem的prop这样的组合和表单中的v-model的用法合二为一,最直观的原因就是:这几个玩意是加在不同的标签上的啊,一种是针对表单的双向绑定,一种是针对el-form和el-form-item的验证(虽然这个验证的数据源最终就是表单那边双向绑定得来的);其次,你感觉一下,一边是利用双向绑定提供数据,另一边是拿到数据和规则进行验证,这两边没有很死板地捆绑在一起啊,类似于耦合度不高,未来自定义或者修改的话会方便很多。
el-form动态修改检验rules后,rule不生效。
1.el-form中watch监视rule并不是深度监视的,所以我们需要直接给整个rule对象重新赋值
;我们在rule对象上直接添加属性,el-form监听不到,不会重新监听事件的。
2.对于有自定义检验规则的不要忘记调用一下callback回调函数,否则检验就会卡在该el-from-item项 。
图见下:
输入明明有值,硬是提示,输入的值不能为空
这里又遇到了其他问题,就是输入明明有值,硬是提示,输入的值不能为空,可按如下步骤排除:
:model="ruleForm" 绑定的ruleForm值是否挂载成功并且操作的是否是这个表单。
:rules="rules" 校验的规则格式绑定的rules是否定义并且格式正确为对象数组。
el-form-item中的prop="name"是否和rules中的name: [ { required: true, message: '请输入活动名称', trigger: 'blur' }, ], 的名称一致,两个name是相同的,element的校验就是根据这个prop找对应的输入框的。
<el-input v-model="ruleForm.name"></el-input>
的v-model="ruleForm.name"确保对象ruleForm中有name这个属性!
el-from-item使用自定义组件绑定的值有但不会触发el-form的rule检验
因为el-from-item只会监听‘el.form.blur’ 和‘el.form.change’这两个事件,自定义组件可能不能自动emit这两个事件。可选择手动触发
el-from的resetForm()的作用
todo
Vue 是异步执行 DOM 更新的(this.$nextTick()的使用)
在执行异步任务队列前,会清空当前执行栈中的所有同步任务(其实就是任务队列吗)
简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
this.$nextTick()方法主要是用在随数据改变而改变的dom应用场景中,vue中数据和dom渲染由于是异步的,
所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。(一般是我们使用的ui框架)
- 需要注意的是,在 created 阶段,如果需要操作渲染后的视图,也要使用 nextTick 方法。
- 注意
mounted
不会保证所有的子组件也都被挂载完成。(但是mounted
生命周期执行的时候,普通dom是肯定已经挂载完成的)如果你希望等到整个视图都渲染完毕(一般是子组件渲染)再执行某些操作,可以在mounted
内部使用 vm.$nextTick:
mounted: function () {
this.$nextTick(function () {
// 仅在整个视图都被渲染之后才会运行的代码
})
}
- mounted 不会保证所有的子组件都渲染完成。(大部分情况下是所有子组件都渲染完成了。)
element-ui 框架使用问题
在 dialog中,由于其是懒加载的所以 默认 slot 不会渲染到其dom,但是el-dialog的默认slot的中的子组件 会被执行其的 created和mounted等一系列等生命周期;
所以就导致了 我们在dialog打开的时候 其默认slot里的图表会看不到等问题
el-dialog 里 默认slot的子组件的生命周期会执行两遍问题是由于el-dialog的懒加载问题形成的吗
vue2中casader的点击事件在vue3中变为了togglePopperVisible事件。
destroy-on-close 关弹窗触发了子组件的mounted
详见此文
设置destroyOnClose=true并不会如同element官方文档描述的这样
而是刷新
dialog内部的元素。
这属于是element官方文档措辞不严谨的问题。
解决:
如果你的需求只是销毁dialog中的元素,那么拉黑该属性,改用v-if。
vant 框架使用问题
van-uploader 图片回显
回显时候需要构造一个属性名为content,content值为base64的对象并放入fileList中传给van-uploader;使用url这个属性赋值为一个地址或者blob,van-uploade是无法回显的
fetch(baseUrl + "/file/" + item.Directory, {
headers: {
// "Content-Type": "application/json",
AccessId: "achance",
Timestamp: new Date().getTime(),
Sign: md5("ach8850925" + new Date().getTime())
}
})
.then(res => {
if (res.status == 200) {
res.blob().then(blob => {
item.name = item.SourceName || item.Name;
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = () => {
const base64 = reader.result;
item.content = base64;
item.isImage = true
this.fileList.splice(index, 1, item);
this.$forceUpdate()
};
reader.onerror = error => reject(error);
});
// this.fileList.splice(index, 1, item);
}
})
.finally(() => {
this.loading = false;
});
天禹老师vue总结
- vue中父亲给儿子传递数据 可以采用props的方式传递一个函数给儿子。儿子组件调用这个函数
- vue中 如果props传递的数据,不要直接改变。会报错。但vue默认的是轻校验。如果你传递的是一个对象如下:
const s={
name:'zhangsan',
ageL:23
}
:receive=s
//我们在子组件里改变s,只要不改变s的引用地址,vue就不会报错。
可以这样改变
s.name='lishi';
s.age=22;
3.由于js中函数没有重载的这一说。所以在vue的methods中。下面只是定义了一个函数。因为底下的那个函数把上面的函数给覆盖了。
methods:{
getBus(v){
console.log(v)
}
getBus(){
cosole.log('我是getbus函数哈')
}
},
自定义事件
组件实例销毁后,原生的dom事件仍可以被调用,但是我们的自定义事件不会被调用了。
原生的dom事件,比如@click加上的事件。虽然原生的dom事件仍可以调用,但是这些事件带来的数据更新变化不会在同步到vue页面上了。
<Student @click="click"/>
在组件上写原生的dom事件也会被vue认为是自定义事件,需要这样写@click.native="click"
全局事件总线
this.$EventBus.$off('eventt',()=>{
//这里这个回调里的this是什么,区别于发布与订阅里的回调的this。
console.log(this)
})
vuex中模块化+namespaced
如果在模块化进程中,如果不写namespaced:true属性,那么每一个模块化中的getters都会被保存到$store的getters属性中,可以直接用...mapGetters(['manCount'])来映射getters,而不用需要关心模块化分类问题。因为所有的getters属性都被放到了$store的getters。
不写namespaced:
getters:{
manCount: (...)
personNn: (...)
}
写了namespaced:true,
getters:{
countAbout/manCount: (...)
personAbout/personNn: (...)
}
路由router
跳转路由并携带参数,to的字符串写法
<router-link :to="`/home/message/detail?id=${m.id}&message=${m.message}`">{{m.message}}</router-link>
因为我们在to前面加了冒号,所以vue把引号里面的东西当成了js去解析。所以即使写成这样,:to="/home/message/detail?id='m.id'&message='m.message'" 会解析错误,因为js里面定义一个变量不会这样定义 const to="/home/message...",js里是不允许带斜杠的,所以我们加上``,使用模板字符串来解析。在更深入一层,在模板字符串里使用js变量的话,我们可以使用${},这种来读取变量。所以就造就了上面的写法
-
name属性与parmas属性在一起用。如果parms与path属性一起用会导致失效。
name: 'detail1',
params:{
id:m.id,
message: m.message
}
起别名的引用
使用了 alias之后,如果不是在script里使用,而是在其他对应的标签里,
比如vue template模板里的image标签使用‘src’属性时,或者在style标签里引入其他的样式时,我们需要加上'~'
<style lang='scss' scoped>
@import '~style/mixin';
</style>
或者vue模板里
<template>
<div>
<iamge src="~@/assets/img/people.png">
</iamge>
</div>
</template>
vue 动态设置img的src地址无效问题
export default {
name: "HelloWorld",
data() {
return {
logo:require("./assets/logo.png"),
};
}
};
</script>
因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require
vue 带boolean类型的参数跳转路由时,会进行类型转化吗?
版本问题,我试了3.5.1是转成字符的,3.1.3是没有转直接使用
你可以看下vue-router源码中resolveQuery部分。从3.4.0开始就转成字符了。
理论上是应该转成字符的,正如我下面所说的,query是拼接在url上的,3.4.0前是直接使用push传递来的参数,但是这样在刷新时会从url解析出query对象就会发现类型又被转成字符了
大群:我把两个项目的路由版本截图贴到提问的最后了,
都是3.1.2版本
的,用的ant-design-vue pro的框架
zangeci:@大群 版本一致应该不会有不一样的行为,你打个断点看下,就在我说的那个函数里边
大群:@zangeci 好,我试试
大群:@zangeci 我看了看源码里,确实是一个做了处理一个没做
,这两个的resolveQuery方法有差别,奇了怪了哈哈,明明是同一个版本的。谢谢啦!
zangeci:@大群 你可以看看源码的版本号注释,是不是更新了版本但是没更新package.json
1.正则表达式二次调用无效
computed:{
rightPhoneNumber(){
var reg = /^1\d{10}$/gi;
console.log(reg.test(this.phoneAccount))
return reg.test(this.phoneAccount)
}
}
再上面的vue的计算属性里,可以打印出正则最后匹配的true,但是返回值一直是false,因为正则调用test()两次后,它的lastIndex改变了。。
test() 方法是正则表达式的一个方法,用于检测一个字符串是否匹配某个模式.
test 方法检查字符串是否与给出的正则表达式模式相匹配,如果是则返回 true,否则就返回 false。
每个正则表达式都有一个 lastIndex 属性,用于记录上一次匹配结束的位置.
语法:regexp.test(str)
在全局匹配模式下
对于同一个正则对象重复调用就会出现下一次的匹配位置从上一次匹配结束的位置开始,解决方法重置lastIndex为0
let reg = /^[\d]{2}$/g;
let str = "12";
console.log(reg.test(str)); //返回true
let = "123";
console.log(reg.test(str)); //从数字3开始匹配,只有一个数字,故返回false
重置lastIndex为0
let reg = /^[\d]{2}$/g;
let str = "12";
console.log(reg.test(str)); //返回true
let = "123";
reg.lastIndex = 0;
console.log(reg.test(str)); //返回true
在非全局匹配模式下,则不存在这个问题
let reg = /^[\d]{2}$/;
let str = "12";
console.log(reg.test(str)); //返回true
let = "123";
console.log(reg.test(str)); //返回true
另外,test()方法和数组的forEach()方法一起使用可能达不到预期结果,在for循环下,同样如此,如下
let line = '1a 123 123 12';
let lines = line.split(' ');
let reg = /^[\d]+$/g;
let res = 0;
lines.forEach( function(element, index) {
console.log(reg.test(element)); // flase true 交替出现
});
使用forEach方法对数组中字符串进行test测试,会出现flase true 交替出现的现象,先出现false还是true则取决数组第一个元素匹配的结果。
同样的,在非全局匹配模式下,则不存在这个问题,这里去掉全局匹配g才可得到预期结果
let line = '1a 123 123 12'
let lines = line.split(' ');
let reg = /^[\d]+$/;
let res = 0;
lines.forEach( function(element, index) {
console.log(reg.test(element)); // false true true true
});
template标签可以少渲染一个外部标签
<div class="index">
<template v-for="item in list"> //这里使用的template
<div>{{ item.id }}</div>
<div>{{ item.name }}</div>
<div>{{ item.music }}</div>
</template>
</div>
做v-for列表循环时 可以看到template并没有被渲染,相较于使用div 会节省一个没必要的div标签的空间。
template是作为占位符模板,用于包裹元素,自身并没有被渲染出来。
深度选择器的使用
在vue中,>>>是深度选择器,可以作用到子组件中的样式,/deep/和::v-deep都是>>>的别名,在scss中不识别/deep/, 可以使用::v-deep
vue中的 scss使用::v-deep,vue3 中scss使用:deep()来代替::v-deep
vue中的页面加载慢问题
el-form表单太多的 如果安装了Vue.js devtools并且打开了控制台,那么页面加载会很卡
vue的路由懒加载
vue中路由懒加载有两种模式
- vue异步组件实现懒加载
routes: [
{
path: '/',
name: 'HelloWorld',
component: resolve=>(require(["@/components/HelloWorld"],resolve))
}
]
- es6的动态导入(Dynamic Import)功能
const Home = () => import('./views/Home.vue')
上述代码中,import() 函数用于动态导入 Home.vue 组件。当路由被触发时,该组件才会被异步加载。
一般懒加载配合代码拆分来使用