十三、idea 开发 vue
idea 中安装 Vue 插件 (2023 版本已经无需安装,自带就有)

然后使用 idea 打开之前创建的 vue 项目

启动项目

方案 1: 点击旁边按钮启动
方案 2: 下方终端输入命令 npm run serve
如上,如果脚本改成 dev, 那么就需要改成命令为 npm run dev
idea 中的终端无法执行 npm run serve 启动项目,提示 npm 不是内部或外部命令解决方案 1: 以管理员身份启动 idea, 打开项目运行
解决方案 2: 不要使用 powershell, 也就是 ps 方式执行 cmd, 换成默认的 cmd
十四、单文件组件【重点】
14.1 介绍
以前
以前是创建了很多.html 的文件组成一个完整项目
现在
vue 项目中是只有一个页面,是一种 spa (单页面程序)
如何实现,一个页面实现整个项目?
就是使用各种组件组装成一个页面. ****
但是,昨天学的组件
使用 Vue.component 来定义全局组件,紧接着用 new Vue ({el: '#app'}) 在每个页面内指定一个容器元素。或者在 Vue 对象内本地注册组件
这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。
但当在更复杂的项目中,或者你的前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显:
- 全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复
- 字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的
\- 不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
- 没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,如 Pug (formerly Jade) 和 Babel
现在文件扩展名为 **.vue** 的 single-file components (单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 webpack 或 Browserify 等构建工具。
单文件组件的组成结构:
- template 组件的模块区域 (html)
- script 业务逻辑区域 (js)
- style 样式区域 (css)
14.2 使用
在工程的 src/components 下创建一个 Demo1 单文件 Demo1 就是自定义的组件
创建后好,组件内部结构
正常的写代码
html
<template>
<!-- 组件的模板,要求只能有一个根元素 -->
<div>
<h1>组件的模板</h1>
<p>取出数据: {{ msg }}</p>
<button @click="dianji">按钮</button>
<p>计算属性: {{ reverseMsg }}</p>
</div>
</template>
<script>
export default {
name: "Demo1", // 组件的名称
data() { // 组件的data数据,只能是函数,不能是对象,且必须返回一个对象,数据放在return的对象中
return {
msg: '组件的data数据'
}
},
methods: {
dianji() {
alert("按钮被点击了")
}
},
// 组件的计算属性
computed: {
reverseMsg() {
return this.msg.split('').reverse().join('')
}
}
}
</script>
<style scoped>
div{
color: red;
}
</style>
组件定义完毕后,需要在其他页面使用
在 HomeView.vue 中使用
- 哪里使用组件,哪里注册
- 注册完,组件名当标签用

注意:
其中./ 是相对路径,@是从根路径
html
// @是从根路径
import Demo1 from "@/components/Demo1.vue";
// ./ 是相对路径
import Demo2 from "./components/Demo2.vue";
十五、Vue 组件间的参数传递 [熟悉]
15.1 父传子 [熟悉]
父组件中使用子组件时,在标签内设置属性

传递是数字,布尔值需要 v-bind:【真实麻烦 】
传递是变量也需要 v-bind:
子组件中设置 props 接收传递过来的数据即可

15.2 子传父 [了解]
使用组件中的 props 属性是无法完成子组件向父组件传值的
那么,如果需要子组件向父组件传递值该如何做?
- Vue 提供了方案: 在子组件中使用自定义事件向父组件传递数据.
具体步骤
- 子组件通过 **$emit** 函数将数据发给父组件
this.$emit (' 父组件中使用子组件时定义的事件名 ', 数据)
- 父组件在使用子组件的时候,定义一个 @事件,这个事件名是 $emit 中自定义的事件名
- 父组件中,需要设计这个 @事件的响应函数,函数中设计参数,这个参数就是子组件传递过来的数据
需求:子组件中设置输入框,输入完,点击按钮,将数据传递给父组件
html
<template>
<div>
我是子组件Son,我收到了父组件的参数:
姓名:{{name}}
年龄:{{age}}
老家:{{home}} <br>
<input type="text" v-model="num">
<button @click="sendNum">发送给父组件</button>
</div>
</template>
<script>
export default {
name: "Son",
props:["age","name","home"],
data() {
return {
num:null
}
},
methods: {
sendNum(){
// 1 子组件向父组件传递数据,使用事件触发
// this.$emit("父组件中自定义的事件名",要传递的数据)
this.$emit("receiveData",this.num)
}
}
}
</script>
<style scoped>
</style>
父组件中,在子组件标签定义自定义事件准备接收子组件发来的数据
html
<template>
<div>
<h2>我是Father组件</h2>
<span>从儿子组件传递过来的数据:{{num}}</span>
<!-- 这里是Father组件,使用子组件son-->
<!-- 给组件传参,就是设置自定义属性 -->
<!--@receiveData是自定义事件-->
<Son :age="18" name="曹丕" :home="home"
@receiveData="getSonNum"></Son>
</div>
</template>
<script>
import Son from "@/views/Son.vue";
export default {
name: "Father",
components: {Son},
data() {
return {
home:"魏国许都",
num:null
}
},
methods: {
getSonNum(num){
console.log("我是Father组件,我收到了子组件传递过来的数据:",num)
this.num = num;
}
}
}
</script>
<style scoped>
</style>
执行流程解析

十六、Vue-router 路由【重点】
16.1 介绍
路由的本质就是一种对应关系,比如说我们在 url 地址中输入我们要访问的 url 地址之后,浏览器要去请求这个 url 地址对应的资源。
那么 url 地址和真实的资源之间就有一种对应的关系,就是路由。

根据不同的事件来显示不同的页面内容
16.2 Vue 的路由 (先了解,学过后再回头细看!!!)
Vue 默认属于单页面的程序,主要通过 URL 中的 hash 来实现不同页面之间的切换。这种切换方式称作前端路由。
Vue 中使用路由的方式,现在是通过使用 Vue 的核心插件 VueRouter 实现的
Vue Router的核心作用
跳转/切换页面
声明式 (写标签)
- <router-link to="要跳转的组件名称">
编程式 (写代码)
- this.$router.push("要跳转的组件名称")
跳转携带数据
声明式导航传递参数通过路径拼接的
/about/1001
在index.js的路径中 通过/about/:id 绑定数据
接收 this.$router.params.参数名
编程式导航实现传递参数
传递 this.$router.push({path:'路径',query:{参数名:值,...}})
接收 this.$router.query.参数名
路由模式
hash模式:监听浏览器地址hash值变化,执行相应的js切换网页;
history模式:利用history API实现url地址改变,网页内容改变;
它们最明显的区别就是hash会在浏览器地址后面增加#号
16.3 安装路由模块

使用命令:
html
npm install vue-router
# 如果报错,可能是npm版本过高,存在兼容性问题,那么使用如下命令
npm install --legacy-peer-deps vue-router@3.5.2
npm install --legacy-peer-deps vue-router@3.1.3
ps: 今天练习过一次以后,后续在创建项目时可以直接选择路由部分内容,创建出的项目直接就配置好了
16.4 解读 AboutView 和 HomeView 的路由
路由入口/切入点
声明式写标签开始路由
或者是编程式写js开始路由
路由匹配规则/映射表
- src/router/index.js
展现该页面(路由的出口)
- <router-view>



16.5 演示:声明式路由 [重点]
需求:新增一个按钮 / 链接,点击实现切换个人信息页面

16.5.1 创建 MyInfo.vue
路由页面建议创建在 **src/views/** 下
components 文件夹下是公共组件
views 文件夹下是 路由组件
html
<template>
<div>
<h1>MyInfo</h1>
<p>这是个人信息页面</p>
<img src="../assets/James.png" alt="詹姆斯高斯林">
</div>
</template>
<script>
export default {
name: "MyInfo",
data() {
return {}
},
methods: {}
}
</script>
<style scoped>
</style>
16.5.2 设置路由入口
在 App.vue 页面中设置声明式路由

16.5.3 设置映射规则
在 **/src/router/index.js** 文件
填充以下内容
javascript
import Vue from 'vue';
import Router from 'vue-router';
import myInfo from "@/views/MyInfo.vue";
Vue.use(Router)//引入路由
export default new Router({
// 路由规则
routes: [
{
path: '/home',//路由地址
name: 'Home',
component: () => import('@/views/Home.vue') // 跳转到这个组件
},
{
path: '/info',//路由地址
name: 'MyInfo',
component: myInfo // 跳转到这个组件
},
]
})

注意写完 route 的 index.js 之后 没用 一定找到 main.js 将 router 进行挂载
16.5.4 设置路由填充位 (展现)
App.vue 中设置路由展示位<router-view>
在哪个页面设置展示位<router-view> , 组件就在哪个页面展示出来

16.6 演示:编程式路由 [重点]
刚才演示的是声明式路由,现在使用编程式路由
演示:公告页面切换

16.6.1 创建公告页 Note.vue
javascript
<template>
<div>
<h1>公告页面</h1>
<ul>
<li>"东风-5C烧饼 吸引范围覆盖全网"新</li>
<li>空军航空开放活动最新剧透来了</li>
<li>公安部公布10起网络违法犯罪案例</li>
</ul>
</div>
</template>
16.6.2 设置路由入口 (编程式路由)
App.vue 设置标签,绑定事件,事件触发函数,函数内编写代码实现路由
this.$router.push ("/ 路径")
这个函数的作用类似 <router-link to="">

- 这里写的是this.$router
- 不是this.$route !!!!!!
16.6.3 src/router/index.js 设置路由规则

16.6.4 bug: 第一次点击跳转没事,再点一次报错
解决:
- 方式 1: 设置异常捕获
javascript
// 在router中的index.js中加上以下代码,注意加在use之前写
const routerPush = VueRouter.prototype.push;
VueRouter.prototype.push = function (location) {
return routerPush.call(this, location).catch((err) => {});
};
方式 2:
在编程式是路由,即 this.$router.push () 修改成这样
javascript
const currentRoute = this.$router.currentRoute;
if (currentRoute.path !== '/note') {
this.$router.push({
path:"/note"
})
}
16.7 路由跳转时参数的传递
16.7.1 声明式路由传参 (路径里面拼数据)
演示 App.vue 中将数据传递给 MyInfo.vue
在路由跳转时路径中传参
javascript
<!--演示声明式路由传参数
1) 路径中设置参数
2) 路由映射规则中设置变量承载参数
3) 可以在组件中通过$route.params获取参数
-->
<router-link to="/info/9527" tag="button">Info信息</router-link> |
在路由表的规则中设变量

在 MyInfo.vue 中接参
使用 this.$route.params.xxx 接收参数
html
<template>
<div>
<h1>MyInfo</h1>
<p>这是个人信息页面</p>
<!--获取路由参数,此处的id是路由映射规则中设置的变量-->
<p>当前路由参数id: {{ this.$route.params.id }}</p>
<p>当前路由参数id: {{ uid }}</p>
<img src="../assets/James.png" alt="詹姆斯高斯林">
</div>
</template>
<script>
export default {
name: "MyInfo",
data() {
return {
uid: this.$route.params.id
}
},
methods: {}
}
</script>
<style scoped>
</style>
16.7.2 编程式路由传参
演示 App.vue 中将数据传递给 Note.vue
App.vue 的编程跳转 js 中设置要传递的数据
javascript
methods:{
toNote(){
this.$router.push({
path:"/note",
query: { //通过query携带数据,最终url /note?username=老王&password
username:"曹植"
}
})
// 详情看路由官方文档说明https://v3.router.vuejs.org/zh/guide/essentials/navigation.html
}
}
Note.vue 中接收参数
javascript
<template>
<div>
<h1>网站公告</h1>
<span>username --> {{username}}</span>
</div>
</template>
<script>
export default {
name: "Note",
data:function(){
return {
username:this.$route.query.username
// 注意是query,因为是按照路径方式发送,注意查看浏览器url
}
}
}
</script>
16.7.3 总结两种传参方式

16.8 嵌套路由 [重点]
多层多级组件嵌套时的路由

需求:在个人中心组件中,再设置三个链接,可以点击切换 [头像 | 家庭信息 | 学校信息]
代码:
创建三个组件页面 Touxiang.vue,Family.vue,School.vue
.... 省略过程
在 MyInfo 组件中设置路由链接发出请求路径,并且设置路由填充位
javascript
<p>这是个人信息页面</p>
<hr>
<nav>
<!-- 导航链接,设置子路由,
/info/8888 , 是为了匹配路由规则中定义的变量:id
-->
<router-link to="/info/8888/school">学校信息</router-link> |
<router-link to="/info/8888/family">家庭信息</router-link> |
<router-link to="/info/8888/avatar">头像信息</router-link> |
</nav>
<router-view></router-view>
在 router/index.js 中设置 myinfo 组件的子路由 children

设置路由填充 router-view

如果有路径中有数据的话,子组件一样可以取值
16.9 路由重定向 [了解]

16.10 路由守卫 (导航守卫) [重要 | 读懂作用]
官方资料: 导航守卫 | Vue Router (vuejs.org)
自己理解:很像 java 拦截器,这里拦截的路由的进程
路由守卫又分为
- 前置路由守卫 router.beforeEach (to,form,next)
- 后置路由守卫 router.afterEach
javascript
// 创建VueRouter对象,其中配置路由信息
const router = new VueRouter({...})
// 前置路由守卫,即跳转页面前生效,一般都是验证身份/权限
router.beforeEach((to, from, next) => {
console.log("to,要路由取的目的页面",to)
console.log("from,从哪个路由出的",from)
// 相当于放行
next()
// 让这次路由去/login路径
// next("/login")
})
router.afterEach((to, from) => {
console.log("后置守卫")
})
// 导出该对象
export default router
16.11 路由元信息 [了解]
官方资料: 路由元信息 | Vue Router (vuejs.org)
个人理解:路由元信息,就是在路由设置中,定义了一个数据,在路由过程带上这个数据,做一些逻辑上的处理
定义路由元信息

在路由守卫中取出



