Vue3实现一个文档学习网站
项目介绍
本项目主要使用vite+vue3.2+Element Plus框架,是一个较为简单的前端小项目。本项目暂时只有展示功能,没有导出功能,纯粹是为了巩固vue3知识点和组合式API,适合刚入门的小伙伴练手
功能实现
1.使用了vue-axios来请求本地md文件
2.element plus来构建页面框架布局
3.使用marked插件将本地md文件转html,利用vue的v-html指令输出
4.在选项式API的基础上使用组合式API进行重构
5.附带请求聚合数据天气预报接口的weather.vue以及解决跨域请求配置相关参数等,使用前需要更换key
Weather.vue
<template>
<el-container class="container">
<el-header>
<el-input placeholder="请输入" class="input" v-model="city">
<template #prepend>城市名:</template>
</el-input>
</el-header>
<el-main class="main">
<div class="today">
今天:
<span>{{todayData.weather ?? plc}} {{todayData.temperature ?? plc}}</span>
<span style="margin-left:20px">{{todayData.direct ?? plc}}</span>
<span style="margin-left:100px">{{todayData.date}}</span>
</div>
<div class="real">
<span class="temp">{{realtime.temperature ?? plc}}°</span>
<span class="realInfo">{{realtime.info ?? plc}}</span>
<span class="realInfo" style="margin-left:20px">{{realtime.direct ?? plc}}</span>
<span class="realInfo" style="margin-left:20px">{{realtime.power ?? plc}}</span>
</div>
<div class="real">
<span class="realInfo">空气质量:{{realtime.aqi ?? plc}}°</span>
<span class="realInfo" style="margin-left:20px">湿度:{{realtime.humidity ?? plc}}</span>
</div>
<div class="future">
<div class="header">5日天气预报</div>
<el-table :data="futureData" style="margin-top:30px">
<el-table-column prop="date" label="日期"></el-table-column>
<el-table-column prop="temperature" label="温度"></el-table-column>
<el-table-column prop="weather" label="天气"></el-table-column>
<el-table-column prop="direct" label="风向"></el-table-column>
</el-table>
</div>
</el-main>
</el-container>
</template>
<script>
export default {
mounted () {
this.axios.defaults.baseURL = '/myApi'
this.requestData()
},
data() {
return {
city:"上海",
weatherData:{},
todayData:{},
plc:"暂无数据",
realtime:{},
futureData:[]
}
},
watch: {
city() {
this.requestData()
}
},
methods: {
requestData() {
let city = encodeURI(this.city)
//请将这里的key换成自己申请的key,需要身份认证 注册地址:http://apis.juhe.cn/
let api = `/simpleWeather/query?city=${city}&key=f9e73e164c1b8fa00b3146240564b8c6`
this.axios.get(api).then((response)=>{
this.weatherData = response.data
this.todayData = this.weatherData.result.future[0]
this.realtime = this.weatherData.result.realtime
this.futureData = this.weatherData.result.future
console.log(response.data)
})
}
}
}
</script>
<style scoped>
.container {
background: linear-gradient(rgb(13, 104, 188), rgb(54, 131, 195));
}
.input {
width: 300px;
margin-top: 20px;
}
.today {
font-size: 20px;
color: white;
}
.temp {
font-size: 79px;
color: white;
}
.realInfo {
color: white;
}
.future {
margin-top: 40px;
}
.header {
color: white;
font-size: 27px;
}
</style>
如何运行项目:
如何使用vite创建vue3项目就不细说了,百度即可,直接点击下载本项目资源即可
1.首先需要安装node.js,且版本>14,查看node.js版本,直接打开cmd输入node -v
node -v
2.vscode进入vitestudy目录,ctrl+j 快捷键打开终端,输入npm install,重新安装node_modules文件夹中的第三方插件
npm install
3.安装完成后直接输入npm run dev运行即可
npm run dev
当然,我们也可以直接输入vue ui,使用GUI图形界面来运行
vue ui
输入指令后,在图形界面中导入该文件夹,选择任务中的dev运行即可
效果预览
这里以选项式API的实现页面为例:初始化渲染HTML专题下的文本标签这篇文章,点击JavaScript专题将渲染标题为方法与属性的文章内容
项目下载
下载:https://wwt.lanzoul.com/iH1WO0crz5yj 密码:b9wv
注意:Weather.vue在viteStudy文件夹内 viteStudy文件夹为组合式API,study文件夹选项式API
项目总结
首先,采用选项式API能够完美运行,但是本例中组合式API写法存在一个问题
即一级标题点击切换时对应文章标题中的内容没有在页面更新,经过测试发现问题出现在Body.vue 中的watch对topic的监听没有起作用,待解决 记录时间:2022/10/01
初步解决办法:直接将Body.vue中的script内容替换为原来的选项式API内容,即可完美运行,Vue3是支持两种写法并存的。
总之,vue3的新写法其目的是为了将逻辑放在一起,但是对于props等数据需要进行解构后具备响应式这一部分目前还没有吃透,所以记录一下这个问题。
更新
2022/10/03 经过对setup进一步的学习,对于父子组件props有了更深层次的理解,在解决上次遗留的问题之前,先来探讨一下 “子组件props接收父组件传递过来的数据是否是响应式的”
父组件
<div>
<pre>this is Parent Component: {{count}} </pre>
<button @click="changeNum">click</button>
</div>
<Test msg="Vite + Vue" :count="count"/>
子组件:Test.vue
<pre style="color:orange">I successfully received the count passed by the parent component {{count}}</pre>
console.log(props)
console.log(props.count)
watch(props,(newValue,oldValue) => {
console.log(props,props.count,props.items)
return num.value = props.count
})
watch(props.count,(newValue,oldValue) => {
console.log(props,props.count)
})
以上面代码为例,我们使用props接收了父组件传递过来的count,并且在控制台观察初始化挂载中props和props.count中的内容 当父组件的点击事件触发时,test.vue里面的count也是更新的,但是此时test.vue中的watch只监听到了props的变化并打印,而props.count没有反应,也没有报错 初步结论:
当监听对象是props时,可以动态响应,前面有proxy props.count也能发生变化;
当监听对象是props.count,没有发生变化,控制台无法打印任何信息也就是说,
也就是说,从父组件传递过来的props中的数据在组件内部是响应式且会同步更新,监听props是有效的,但监听 props.count没有打印,理论上props.count是props内部属性,应该也会更新的。
解决代码:只需要将监听对象更换为props就ok了
watch(props,(val) => {
console.log('已改变1',props,val)
FileManager.getPostContent(props.topic, props.items[currentIndex.value].title).then((res) => {
content.value = res.data;
})
})
watch(currentIndex,(val) => {
console.log('已改变2',val)
FileManager.getPostContent(props.topic, props.items[val].title).then((res) => {
content.value = res.data;
})
})
最后在网上找到了答案:
const obj = reactive({
count: 0
})
watch(
()=> obj.count,
(newVal, oldVal)=> {
console.log('修改后', newVal)
console.log('修改前', oldVal)
}
)
仔细看上面的()=> obj.count,因此我猜测是语法的问题,如果将props.count写成 ()=> props.count是不是也打印对应结果了。继续思考,为什么这里写成箭头函数呢?
最终结论: 就是语法问题,第一个参数要写成箭头函数,将代码修改为()=> props.count和props都可以解决原来的问题。另外,监听props.count会比监听props先执行!!! 参考链接:Vue3中的watch监听 从这篇文章可以进一步得知为什么要写成箭头函数,因为我们的props接收数据时自动被整合成了一个reactive对象(本项目中props接收了items数组和topic字符串),哪怕props里面只有单个数据,也是reactive对象。
如果使用setup语法糖,props的引入方式是这样的
import { ref, reactive,defineProps,watch } from 'vue'
const props = defineProps({
count: ''
})
项目参考链接
针对组合式API和Weather.vue
vite.config.js如何配置多个跨域
手把手教你vue3引入vue-router路由
【VUE】vue3+vite中process.env的配置方法
Vue3 组合式 API 大全
vue3怎引入子组件
Vue3 setup中如何使用计算属性computed , 父子组件如何传值
|