记录工作中的一些笔记,以便日后回顾
1. 单行文本溢出省略
- 核心 CSS 语句
overflow: hidden
;(文字长度超出限定宽度,则隐藏超出的内容)white-space: nowrap
;(设置文字在一行显示,不能换行)text-overflow: ellipsis
;(规定当文本溢出时,显示省略符号来代表被修剪的文本)
css
<div class="wrap">
<div class="content">测试数据:css单行文本超出长度显示省略号--明天也要努力</div>
<div class="content text-ellipsis">测试数据:css单行文本超出长度显示省略号--明天也要努力</div>
</div>
<style>
.wrap{
width: 200px;
height: 200px;
}
.content{
width: 100%;
margin-top: 6px;
}
.text-ellipsis{
overflow:hidden;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow:ellipsis;
}
</style>
v-html
使用时,省略样式失效,可以使用filter。
js
filters: {
//当渲染的文字超出9字后显示省略号
ellipsis(value) {
value = value.replace(/<.*?>/gi, '') //把v-html的格式标签替换掉
if (value.length > 50) {
return value.slice(0, 50) + '...'
} else {
return value
}
},
},
2. 回顾CSS盒子模型
标准模型和IE模型的区别,如何设置标准模型、IE模型
- 两者的区别在于
content
的不同,
- IE盒模型的
content
包括border、padding
- 标准模型元素宽度width=content,高度计算相同
- 切换
css
html * {
box-sizing: border-box; // 设置为IE模型
box-sizing: contetn-box; // 设置为标准模型
}
3. 关于vue的 this.$refs.xxx 打印为undefined解决办法
今天做项目的时候发现,明明this.$refs
里面有东西,如下图,但是打印this.$refs.xxx
的时候却是undefined,
用 ref
注册子组件,父组件可以通过this.$refs.xx.fn
调用子组件里的函数, vue 官网中ref
下有一段话
- 关于
ref
注册时间的重要说明:因为ref
本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在!
$refs
也不是响应式的,因此你不应该试图用它在模板中做数据绑定。
解决方法:
1、如果你在mounted
或者created里获取this.$refs
,因为dom还未完全加载,所以你是拿不到的, updated 阶段则是完成了数据更新到 DOM 的阶段(对加载回来的数据进行处理),此时,就可以使用this.$refs
了。
2、如果写在(方法)method中,那么可以使用 this.$nextTick(() => {})
等页面渲染好再调用this.$refs.xxx
,这样就可以了。如下图
4. NextTick
回顾
官方对其的定义
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
什么意思呢?
我们可以理解成,Vue
在更新 DOM
时是异步执行的。当数据发生变化,Vue
将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新 举例一下
Html
结构
html
<div id="app"> {{ message }} </div>
构建一个vue
实例
js
const vm = new Vue({
el: '#app',
data: {
message: '原始值'
}
})
修改message
js
this.message = '修改后的值1'
this.message = '修改后的值2'
this.message = '修改后的值3'
这时候想获取页面最新的DOM
节点,却发现获取到的是旧值
arduino
console.log(vm.$el.textContent) // 原始值
这是因为message
数据在发现变化的时候,vue
并不会立刻去更新Dom
,而是将修改数据的操作放在了一个异步操作队列中
如果我们一直修改相同数据,异步操作队列还会进行去重
等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM
的更新
4.1为什么要有nexttick
举个例子
js
{{num}}
for(let i=0; i<100000; i++){
num = i
}
如果没有 nextTick
更新机制,那么 num
每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图),有了nextTick
机制,只需要更新一次,所以nextTick
本质是一种优化策略
4.2使用场景
如果想要在修改数据后立刻得到更新后的DOM
结构,可以使用Vue.nextTick()
第一个参数为:回调函数(可以获取最近的DOM
结构)
第二个参数为:执行函数上下文
js
// 修改数据
vm.message = '修改后的值'
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {
// DOM 更新了
console.log(vm.$el.textContent) // 修改后的值
})
组件内使用 vm.$nextTick()
实例方法只需要通过this.$nextTick()
,并且回调函数中的 this
将自动绑定到当前的 Vue
实例上
js
this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '修改后的值'
})
$nextTick()
会返回一个 Promise
对象,可以是用async/await
完成相同作用的事情
js
this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
await this.$nextTick()
console.log(this.$el.textContent) // => '修改后的值'
4.3实现原理
源码位置:/src/core/util/next-tick.js
callbacks
也就是异步操作队列
callbacks
新增回调函数后又执行了timerFunc
函数,pending
是用来标识同一个时间只能执行一次
js
export function nextTick(cb?: Function, ctx?: Object) {
let _resolve;
// cb 回调函数会经统一处理压入 callbacks 数组
callbacks.push(() => {
if (cb) {
// 给 cb 回调函数执行加上了 try-catch 错误处理
try {
cb.call(ctx);
} catch (e) {
handleError(e, ctx, 'nextTick');
}
} else if (_resolve) {
_resolve(ctx);
}
});
// 执行异步延迟函数 timerFunc
if (!pending) {
pending = true;
timerFunc();
}
// 当 nextTick 没有传入函数参数的时候,返回一个 Promise 化的调用
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve;
});
}
}
timerFunc
函数定义,这里是根据当前环境支持什么方法则确定调用哪个,分别有:
Promise.then
、MutationObserver
、setImmediate
、setTimeout
通过上面任意一种方法,进行降级操作
js
export let isUsingMicroTask = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
//判断1:是否原生支持Promise
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
//判断2:是否原生支持MutationObserver
let counter = 1
const observer = new MutationObserver(flushCallbacks)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
//判断3:是否原生支持setImmediate
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
//判断4:上面都不行,直接用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
无论是微任务还是宏任务,都会放到flushCallbacks
使用
这里将callbacks
里面的函数复制一份,同时callbacks
置空
依次执行callbacks
里面的函数
js
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
小结:
- 把回调函数放入callbacks等待执行
- 将执行函数放到微任务或者宏任务中
- 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调
5. Vue 子组件使用 this.$parent 无法访问到父组件数据和方法
- 实际场景是父组件有一个
dialog
弹出框,包含几个子组件,根据标识只展示一个子组件。 - 现在要想用
this.$parent
直接调父组件的方法,但没有生效。
解决方法:
后面对着this.$parent
实例一顿找,发现根本就没有父组件的数据和方法,并不是父组件的实例。
因为在子组件外面包了一层dialog弹出框,所以this.$parent
是element
实例,this.$parent.$parent
是父组件实例,
子组件在<template></template>
没有任何包裹时通过this.$parent
可以直接访问到数据方法
子组件用了dialog
弹出框包裹时通过this.$parent.$parent
访问数据和方法(具体看实际情况包了几层)
6. consloe 小技巧
6.1. 使用 console.dir() 打印对象
console.dir()
是一个专门打印 对象 的 API。
console.dir() 方法可以显示指定 JavaScript 对象的属性列表,并以交互式的形式展现。输出结果呈现为分层列表,包含展开/折叠的三角形图标,可用于查看子对象的内容。
因此,当我们打印对象时,可以使用 dir
代替 log
console.log()
输出的是对象源代码,console.dir()
则输出该对象的内容,所有属性和方法。
6.2. 使用 console.table() 打印数组
如果想要打印数组的话,那么 table()
是首选方法:
7.>>>、/deep/、::v-deep、::v-deep()和:deep()的区别与用法
1. >>>
是CSS
原生中的深度选择器
语法,用于穿透样式封装。
仅在某些特定环境(如Webpack
的css-loader
配置中)和原生CSS中有效,Vue单文件组件中通常需要特定配置才能使用。
css
<style scoped>
.parent >>> .child {
/* 样式规则 */
}
</style>
2. /deep/
/deep/
曾经是CSS
中实际提出的新增功能,但之后被删除,所以不建议使用。
css
<style scoped>
.parent /deep/ .child {
/* 样式规则 */
}
</style>
3. ::v-deep是/deep/
的别名深度选择器
。
支持Vue2
,但在Vue3
中不推荐使用。
css
<style scoped>
.parent::v-deep .child {
/* 样式规则 */
}
</style>
4.::v-deep()
::v-deep()
是深度选择器
从Vue2
向Vue3
演化过程中的一个过渡性组合器。
css
<style scoped>
.parent ::v-deep(.child) {
/* 样式规则 */
}
</style>
5. :deep()
:deep()
是Vue3
官方推荐的深度选择器
,不建议使用>>>
和/deep/
以及::v-deep
包括::v-deep()
。
css
<style scoped>
.parent :deep(.child) {
/* 样式规则 */
}
</style>
- 在Vue2 中使用
::v-deep
; - 在Vue3 中使用
:deep()
; /deep/
需要与特定浏览器版本搭配使用,不推荐使用- 部分CSS预处理器 对
>>>
支持不佳,在不使用CSS预处理器时可使用,否则不推荐使用
一步到位,直接展示代码。
8. el-upload图片、视频上传
1. 直接显示上传代码
1.封装上传组件UpLoadFile
js
<template>
<div>
<el-upload
class="avatar-uploader"
:action="uploadUrl" // 上传文件的地址
:headers="{ token: token }" // 上传时需要的请求头,包含token
:show-file-list="false" // 不显示文件列表
:on-success="handleSuccess" // 上传成功后的回调函数
:before-upload="beforeUpload" // 上传前的钩子函数
:on-progress="uploadProcess" // 上传进度的钩子函数
>
<div v-if="!fileFlag && fileType === 'image'"> // 如果不是正在上传的状态且文件类型为图片
<img v-if="fileUrl" :src="fileUrl" class="avatar" /> // 如果有文件URL,则显示图片
<i v-else class="el-icon-plus avatar-uploader-icon" /> // 如果没有文件URL,则显示加号图标
</div>
<div v-if="!fileFlag && fileType === 'video'"> // 如果不是正在上传的状态且文件类型为视频
<video v-if="fileUrl" :src="fileUrl" class="avatar-video" controls="controls"> // 如果有文件URL,则播放视频
您的浏览器不支持视频播放
</video>
<i v-else class="el-icon-plus avatar-uploader-icon" /> // 如果没有文件URL,则显示加号图标
</div>
<el-progress v-if="fileFlag" style="margin-top:10px;" type="circle" :percentage="uploadPercent" /> // 如果正在上传,则显示圆形进度条,显示上传百分比
</el-upload>
</div>
</template>
<script>
export default {
props: {
token: {
type: String,
default: '',
},
uploadUrl: {
type: String,
required: true,
},
fileType: {
type: String,
default: 'image',
},
hasFile: {
type: String,
default: '',
},
},
data() {
return {
fileUrl: '', // 上传成功后接口返回的地址
uploadPercent: 0, // 上传时进度条显示的进度
fileFlag: false, // 显示文件还是进度条的标识
}
},
methods: {
// 上传成功的回调
handleSuccess(res, file) {
console.log('res', res) // 打印上传返回的结果
this.fileFlag = false // 上传结束,重置文件上传标记
this.uploadPercent = 0 // 重置上传进度
if (res.IsSuccess) { // 判断上传是否成功
// 这里是回显的地址自定义拼接
this.fileUrl = '/Content/HomeCarousel/' + res.Data // 拼接上传成功后的文件地址
} else {
// 上传失败,提示用户
this.$message.error('视频上传失败,请重新上传!') // 弹出错误信息
}
},
// 进度条更新方法
uploadProcess(event, file, fileList) {
this.fileFlag = true // 表示文件正在上传中
this.uploadPercent = Math.floor(event.percent) // 更新上传进度
},
// 上传前的文件检查
beforeUpload(file) {
// 检查文件类型是否为图片
const isImage = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg'
// 检查文件类型是否为视频
const isVideo = file.type === 'video/mp4' || file.type === 'video/avi' || file.type === 'video/flv'
// 检查文件大小是否小于 100MB
const isLt10M = file.size / 1024 / 1024 < 100
if (!isLt10M) { // 如果文件超过 100MB
this.$message.error('上传文件大小不能超过 100MB!') // 提示文件大小错误
return false // 取消上传
}
if (!isImage && this.fileType === 'image') { // 如果文件不是图片格式
this.$message.error('上传文件格式有误!') // 提示文件格式错误
return false // 取消上传
}
if (!isVideo && this.fileType === 'video') { // 如果文件不是视频格式
this.$message.error('上传文件格式有误!') // 提示文件格式错误
return false // 取消上传
}
},
},
watch: {
hasFile(val) {
// 检查val是否存在,代表是否上传了文件
if (val) {
// 如果val存在,将fileUrl设置为val,即文件的URL
this.fileUrl = val
} else {
// 如果val不存在,将fileUrl清空
this.fileUrl = ''
}
},
},
}
</script>
<style lang="scss" scope>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 148px;
height: 148px;
line-height: 148px;
text-align: center;
}
.avatar {
width: 148px;
max-height: 148px;
display: block;
}
.avatar-video {
width: 200px;
max-height: 200px;
display: block;
}
</style>
props 中的token
和uploadUrl
根据需要在父组件中传入,因为有时候后台接口要求上传文件时 需要在请求头headers里加入登录标识token
,uploadUrl
为上传文件的接口。fileType
传入image
或video
,在视图中就根据fileType
判断显示img图片标签还是video视频标签。
2. 父组件
直接看图
- 如果需要回显,让子组件直接 uploadFile.vue 直接显示图片或视频,则再多加一个props参数。
父组件parent.vue中添加hasFile
,如果需要回显直接传入需要回显的链接,不需要则为空 代码如下:
js
<div class="cus-img-upload">
<UpLoadFile :token="token"
:upload-url="uploadUrl"
file-type="video"
:has-file="hasFile">
</UpLoadFile>
</div>
data() {
return {
// 视频上传
token: '',
uploadUrl: 'api/Information/UploadFile',
hasFile: '',
}
mounted() {
this.token = this.$cookies.get(this.$member.TOKEN)
},
9. .9
图
在开发提示气泡时,气泡背景要随着文字数量的增加而进行延伸,而这气泡背景便是使用到了.9图
,由UI提供。
点九图(9 patch image) ,是Android开发中用到的一种特殊格式的图片,文件名以" .9.png "命名。这种图片能告诉开发,图像哪一部分可以被拉伸,哪一部分不能被拉伸需要保持原有比例。运用点九图可以保证图片在不模糊变形的前提下做到自适应。点九图常用于对话框和聊天气泡背景图片中。
- 格式
- .9图的后缀格式为:.9.png
- 作用
- .9图可以进行拉伸,如水平、竖直方向的延长,而清晰度不变。
- 令一张图片实现多种拉伸效果,减少UI切图的使用,降低包体积。
PS:工作中用过的一些知识点,自己记录的笔记和整理来网络上的资源 ,方便以后复习使用。