用fetch来接受stream流实现文字逐字展示的效果,
fetch(`url(请求地址)`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',//规定的传输的格式
'Authorization': localStorage.token//携带的token
},
body: JSON.stringify(obj)//请求体中携带的参数
})
.then(res => {
const reader = res.body.getReader();
let index = null
// 处理解析出来的元素进行页面展示
const appendText = (text) => {
if (text != '') {
//滚动到最底部在,每次拼接文字的时候
nextTick(() => {
let dom = document.querySelector('.textAAA') as Element
dom.scrollIntoView(false)
})
// 逐字展示时遇到代码
dailogData.value[(dailogData.value.length - 1)].content += String(text)
}
};
// 读取stream流,reader一次只接受一次相应的数据
const readStream = () => {
reader.read().then(({
done,
value
}) => {
// 是否完成,如果已完成将数据替换为根据真实id查询到的数据
if (done) {
let obj = {
segment_ids: searchGroupId.value
}
getchatlogApi(projectId.value, obj).then((ress: any) => {
ress.items[1] = resertFormat(ress.items[1])
dailogData.value.splice(dailogData.value.length - 2, 2, ...ress.items)
isStatue.value = false
searchValue.value = ''
})
return;
}
const text = new TextDecoder('utf-8').decode(value);
//将下图数据格式处理为想要的格式
let _data = text?.split('\n\n') || [];
for (const it of _data) {
let item = it.replace(/^(data: \[DONE\])|^(data:)/, '');
if (item) {
let res = JSON.parse(item);
if (res.event == 'rename') {
mainStore.leftRoueterItem.name = res.text
}
if (res.event == 'cmpl') {
appendText(res.text);
} else {
searchGroupId.value.push(res.id)
}
}
}
readStream();
});
};
readStream();
})
我的操作是在发出请求后先放上去假数据来创建dom元素,然后将请求到的数据逐字拼接上去,拼接完成之后,再把假数据替换为真实数据,
将此处的格式替换
滚动到底部要注意是给子级加的属性
给overLow元素的子级添加scrollIntoView方法,为true时,顶部,为false时底部
let dom = document.querySelector('.textAAA') as Element
dom.scrollIntoView(false)
2.停止输出
全局声明变量,
let controller = new AbortController();
let signal = controller.signal;
fetch的第二个参数多传一个signal,
当点击停止按钮时, controller.abort();就可以暂停输出了
注意:暂停之后这个变量就不能再进行第二次请求发送了,之后的请求都会被拦截,所以要对变量进行重新赋值,一般是暂停按钮时,或者页面切换时给他暂停操作。