开篇首先感谢我的师傅,谆谆教诲,工作能遇到这么好的师傅,真的很幸运~🙏
1.对象拷贝问题
接口数据的要求,要求传一个数组,数组只有id,seq
并且过滤掉数组中推荐的对象
进行数组对象的转换
async addChannel(obj) {
// 过滤掉推荐对象
const newarry = this.userChannelList.filter((item) => item.id !== 0);
// 接口规范
newarry.forEach((item, index) => {
// 删除对象
delete item.name;
item.seq = index;
});
const data = {
channels: this.newarry,
};
const res = await updateChannelsAPI(data);
if (res.status >= 200 && res.status < 300) {
this.userChannelList.push(obj);
Notify({ type: "success", message: "新增频道成功~" });
}
},
为什么点击新增名字没有了?
- 上面的代码出了问题,新增时名字被删除了
- 原因:所有数组里的对象,都是同一个内存地址,影响到channelEdit.vue中的对象
- 解决方案:需要拷贝出来一份不使用原数组的对象
// 过滤掉推荐对象
const newarry = this.allChannelList.filter((obj) => obj.id !== 0);
// 浅拷贝
const theNewarry = newarry.map((obj, index) => {
const newObj = { ...obj };
delete newObj.name; //删除名称
newObj.seq = index;
return newObj;
});
const data = {
channels: theNewarry,
};
2.编辑状态初始化
<ChannelPopup
:userList="userChannelList"
:unCheckList="uncheckChannelList"
@addChannelEv="addChannel"
@deleteChannelEv="deleteChannel"
@closeEv="closePopup"
ref="editRef"
></ChannelPopup>
// 关闭popup页面
closePopup() {
this.showPopup = false;
// 初始化编辑状态
this.$refs.editRef.isEdit = false;
},
v-moudle的知识点
v-moudle="channelId"
等同于
props:{value:channelId}
自动触发@input事件
3. 输入框自动获取焦点
全局创建自定义指令
<!-- 搜索组件 -->
<van-search
placeholder="请输入搜索关键词"
background="#007BFF"
shape="round"
v-fofo
/>
// 全局自定义指令 main.js
const directiveObj = {
install(Vue) {
// 全局自定义指令 main.js
Vue.directive("fofo", {
inserted(el) {
const theInput = el.querySelector("input");
theInput.focus();
},
});
},
};
Vue.use(directiveObj);
-
实现输入框自动获取焦点
-
注意自定义函数绑定的位置应该在合适的标签中
<textarea placeholder="友善评论、理性发言、阳光心灵" v-fofo></textarea>
出现如下问题
解决,注意自定义指令的位置是否获取正确
//知识点:原生DOM.nodeName 拿到标签名(注意:大写的字符串)
const directiveObj = {
install(Vue) {
// 全局自定义指令 main.js
Vue.directive("fofo", {
inserted(el) {
if (el.nodeName === "TEXTARES" || el.nodeName === "INPUT") {
el.focus();
} else {
// 如果是在自身绑定的话就尝试往里获取一下
const theInput = el.querySelector("input");
const theTextare = el.querySelector("textarea");
if (theInput) theInput.focus();
if (theTextare) theTextare.focus();
}
},
});
},
};
4.输入框防抖
-
什么是防抖 --- 当一个动作连续触发,只执行最后一次请求
-
什么是节流 --- 一个动作在一段时间内只执行一次请求
防抖:
data() {
return {
keyword: "", // 搜索关键字
timer: null, // 防抖定时器
};
},
inputFn() {
// 输入框内容实时改变触发事件的方法
// 防抖:延时执行逻辑代码,事件再次触发时,清除上一个定时器
clearTimeout(this.timer);
this.timer = setTimeout(() => {
if (this.keyword.length === 0) return;
console.log(this.keyword);
}, 1000);
},
5.关键字高亮
关键字高亮如何做?
用replace方法+正则+文字替换span带样式的标签
结果:
修改为v-html后即可获得正确的样式,解析成标签才能成功
而正确的做法其实是如下所示,在获取到替换的值只改变颜色,创建一个正则对象进行全局替换和大小写不区分
keywordColor(searchMsg, keyword) {
/**
* 使用正则表达式进行全文匹配关键词
* ig : 表示 全文查找 ,忽略大小写
* i : 忽略大小写
* g : 全文查找
*
* 使用字符串的replace方法进行替换
* stringObject.replace('被替换的值',替换的值)
**/
if (!searchMsg) return;
const reg = new RegExp(keyword, "ig");
return searchMsg.replace(reg, (match) => {
return `<span style="color:red;">${match}</span>`;
});
},
基本的就已经完成了,如果你想更好的复用的话可以封装起来使用~
好啦,最终就实现完成了~
6.本地存储 (保存历史记录)
因为浏览器本地只能存储字符串,所以存储的时候应该转换为字符串,取出来的时候需要转换为数组,配合监听器使用
坑:路由跳转在watch之前执行,所以应该给路由跳转一个setTimeOut包裹,eventLoop,异步任务的问题
数组去重,使用Set类数组转换实现(如果是对象就是比较对象的内存地址)
data() {
return {
keywordColor,
keyword: "", // 搜索关键字
timer: null, // 防抖定时器
searchList: [], // 关键字列表
history: JSON.parse(localStorage.getItem("his")) || [], // 搜索历史
};
},
// 监听历史记录这个数组的变化
watch: {
history: {
deep: true,
handler() {
// 数组去重 类数组转为真实数组
const theSet = new Set(this.history);
const arry = Array.from(theSet);
// 保存在本地
localStorage.setItem("his", JSON.stringify(arry));
},
},
},
// 点击跳转路由
toSearchResult(keyword) {
// 防止点击历史记录而将历史记录保存到localstorage
const index = this.history.findIndex((item) => item === keyword);
if (index < 0 && keyword.length > 0) {
// 不在历史记录里面就数组第一个元素前存储
this.history.unshift(keyword);
}
// 路由跳转
setTimeout(() => {
this.$router.push(`/searchResult/${keyword}`);
}, 0);
},
// 清空localstorage中指定的数据项
localStorage.removeItem("his");
7.路由传参
// router.js
{
path: "/searchResult/:keyword", // 动态路由传参
component: SearchResult,
},
获取路由参数keyword
// searchResult.vue
this.keyword = this.$route.params.keyword;
7.图片防盗链
- 了解什么是图片防盗链
- 怎么解决该问题
分析
有时候报错403状态码, 发现都是图片路径请求问题
原因
- http请求头中有一个referrer字段,用来表示发起http请求的源地址信息
-
服务器端在拿到这个referrer值后判断请求是否来自本站
- 若不是则返回403,从而实现图片的防盗链。上面出现403就是因为,请求的是别人服务器上的资源,但把自己的referrer信息带过去了,被对方服务器拦截返回了403
解决
在前端可以通过meta来设置referrer policy(来源策略),referrer设置成no-referrer,发送请求不会带上referrer信息,对方服务器也就无法拦截了
<!-- 解决图片403防盗链问题 -->
<meta name="referrer" content="no-referrer" />
但是如果他们做了其他判断, 我们依旧拿不到此图片
小结
-
图片为何会403?
- 在自己的网页里, img的src地址是别人服务器的, 他们做了限制
-
如何解决图片403?
- 在index.html中, 添加meta信息, 不携带referrer给第三方服务器
- 但是如果他们做了其他判断, 我们依旧拿不到此图片
8.点击跳转到详情页
@click.native()
一丶@click.native是给组件绑定原生事件
我的标签 ‘ListCell’ 是子组件引到当前父组件
因为当父组件中引入子组件的时候,当要触发子组件点击事件的时候@click 不生效。
有两种解决方式
1.@click.native
2.在子组件中添加this.$emit ( “事件名” ,value )方法 将子组件的值传到父组件。
怪异盒模型和普通盒模型
content-box:指定盒模型为 W3C 标准模型,设置 border、padding 会增加元素 width与 height 的尺寸,即 border 与 padding 相当于是元素的“殖民地”,元素的“土地”、尺寸会增加,为向外延伸。
border-box:指定盒模型为 IE模型(怪异模式),设置 border、padding 不会影响元素 width 与 height 的尺寸,即 border 与 padding 由元素已设空间转变。即空间还是这个空间,只是将部分空余的地方,转变成了其他空间用法而已,为内部转变。
moment函数
// 封装一个函数 判断时间到现在的天数
import moment from "moment";
export const longTime = (startDay) => {
return moment().diff(moment(startDay), "day");
};
// html
<van-cell center :title="dateSouce.aut_name" :label="diffDay + `天前`">
// js
import { longTime } from "@/utils/moment";
data() {
return {
dateSouce: {}, // 文章详情
};
},
computed: {
diffDay() {
return longTime(this.dateSouce.pubdate);
},
9.滚动页面位置到相应的位置
点击评论按钮滚动到评论列表的第一个,第一条评论到首部
有四种情况
- 内容很高,评论很少
- 内容很少,评论很高
- 内容很少,没有评论
- 内容很多,没有评论
实现步骤:
点击获取内容的高度,并且点击后滚动scroll-y那么多距离
toCommentList() {
// scrollTo里面应该放一个对象,实现动画滚动
const articleHeight =
document.querySelector(".article-container").scrollHeight;
const scrollHeight = articleHeight;
window.scrollTo({ top: scrollHeight, behavior: "smooth" });
},
10.异步事件执行
当点击输入框时输入框获取焦点,当失去焦点后当前输入框组件销毁,点击发布也会失去焦点。
解决:异步事件,点击发布后再销毁组件
<!-- 底部添加评论区域 - 2 -->
<div class="cmt-box van-hairline--top" v-else>
<textarea
placeholder="友善评论、理性发言、阳光心灵"
v-fofo
@blur="blurFn"
v-model.trim="commentText"
></textarea>
<van-button
type="default"
:disabled="commentText.length === 0"
@click="sendComment"
>发布</van-button
>
</div>
blurFn() {
//销毁dom延迟,点击事件先执行后再执行,异步代码
setTimeout(() => {
this.isShowComment = true;
}, 0);
},