@TOC
前言
本文将深入探讨 Vue 组件的精髓,从组件的定义、动态组件的使用、父子组件的交互与传参等方面展开,帮助读者深入理解 Vue 组件化的设计理念与实现方法。此外,我们还将详细介绍 Vue 路由的常见操作,包括 router.push
、router.replace
、router.go
等方法的使用,以及路由对象属性 $route.path
、$route.params
、$route.query
、$route.fullPath
的含义与应用。
一、Vue组件
1. 组件的定义
组件系统 是
Vue.js
其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树 :功能组件 (
Component
) 是 Vue.js 最强大的功能之一。组件可以扩展HTML
元素,封装可重用的代码。
- 在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。
- 在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。
- 所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子
2. 动态组件的使用
组件名应该始终是多个单词的,根组件 App 除外
这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的单文件组件的文件名应该要么始终是单词大写开头 (PascalCase
),要么始终是 (kebab-case
)混用文件命名方式,有的时候会导致大小写不敏感的文件系统的问题,这也是横线连接命名同样完全可取的原因。使用 kebab-case:
当使用kebab-case
(短横线分隔命名)定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如<my-component-name>
Vue.component('my-component-name', { /* ... */ })
使用 PascalCase:
当使用PascalCase
(驼峰式命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说<my-component-name>
和<MyComponentName>
都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的.Vue.component('MyComponentName', { /* ... */ })
组件注册:
//在要展示的页面 导入组件,并注册
<script>
import my_comp from './my-comp'
export default {
data(){
return{
}
},
components:{
'Mycomp': my_comp
}
}
</script>
// 在要展示的地方加入下面这行代码
<Mycopm></Mycopm>
3. 父子组件
父子组件使用
在vue组件通信中其中最常见通信方式就是父子组件之中的通性,而父子组件的设定方式在不同情况下又各有不同。最常见的就是父组件为控制组件,子组件为视图组件。父组件传递数据给子组件使用,遇到业务逻辑操作时子组件触发父组件的自定义事件。
父组件到子组件通讯
父组件到子组件的通讯主要为:子组件接受使用父组件的数据,这里的数据包括属性和方法(String, Number, Boolean, Object, Array, Function)。vue提倡单项数据流,因此在通常情况下都是==父组件传递数据给子组件使用,子组件触发父组件的事件,并传递给父组件所需要的参数==
父子组件传参
通过 [props]传递数据 (推荐)
父子通讯中最常见的数据传递方式 就是通过props传递数据,就像方法的传参一样,父组件调用子组件并传入数据,子组件接受到父组件传递的数据进行验证,使用props (可以是数组或对象)用于接收来自父组件的数据。
ps:props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义校验和设置默认值
<!-- 父组件 -->
<template>
<div>
<my-child :parentMessage="parentMessage"></my-child>
</div>
</template>
<script>
import MyChild from '@components/common/MyChild'
export default {
components: {
MyChild
},
data() {
return {
parentMessage: "我是来自父组件的消息"
}
}
}
</script>
<!-- 子组件 -->
<template>
<div>
<span>{
{ parentMessage }}</span>
</div>
</template>
<script>
export default {
props: {
parentMessage: {
type: String,
default: '默认显示的信息'
// require: true // 必填
}
}
}
</script>
子父组件传参
通过$emit
传递父组件数据 与父组件到子组件通讯中的$on
配套使用,可以向父组件中触发的方法传递参数供父组件使用。
<!-- 父组件:一旦触发子组件时,事件child-event就调用parentEvent打印data -->
<template>
<div>
<!-- 子组件传递数据给父组件 -->
<my-child @child-event="parentEvent"></my-child>
</div>
</template>
<script>
import myChild from "./MyChild.vue";
export default {
name: "ParentEl",
data() {
return {
msg: "我是父元素的组件",
};
},
components: {
myChild,
},
methods: {
// 父组件方法, data是子组件传递的数据
parentEvent(data) {
console.log(data);
},
},
};
</script>
<style lang="scss" scoped></style>
<!-- 子组件:一旦点击按钮,就调用toParent函数,toParent函数发送事件child-event并传递数据"我是子组件传递给父组件的"给父组件 -->
<template>
<div>
<!---触发事件给父组件传值 -->
<button @click="toParent">点击实现传值给父组件</button>
</div>
</template>
<script>
export default {
name: "myChild",
methods: {
toParent() {
// 使用$emit传值,this.$emit(事件, 数据)
// 子组件通过$emit发送一个事件给父组件 (click,change)
// $emit(参数1, 参数2); 参数1:发送的事件名 参数2:发送的数据
this.$emit("child-event", "我是子组件传递给父组件的");
},
},
};
</script>
<style lang="scss" scoped></style>
二、Vue路由
1. 常见路由操作
<router-link>
组件支持用户在具有路由功能的应用中单击导航。
- 通过
to
属性可以指定目标地址,默认渲染成带有正确链接的<a>
标签,通过配置tag
属性可以生成别的标签。- 另外,当目标路由成功激活时,链接元素会自动设置一个表示激活的
css
类名。
<!-- 直接给to指定属性值, 不提倡使用,尽量使用属性绑定 -->
<router-link to='/goods'>商品</router-link>
<!-- 使用v-bind 绑定 JS表达式-->
<router-link :to="'/goods'">商品</router-link>
<!-- 绑定data中的变量path -->
<router-link :to='path'>商品</router-link>
<!-- 绑定对象,自定义网址,携带查询参数 ==> /goods?id=1 -->
<router-link :to="{
'path':'/goods', query:{
'id':1}}">商品</router-link>
<!-- 绑定 对象,命名路由,携带params参数 ==> /goods/1 -->
<router-link :to="{name:'goods', params:{
'id':1}}">商品</router-link>
router.push
router
是VueRouter
的一个对象,通过Vue.use(VueRouter)
和VueRouter
构造函数得到一个router
的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。
router.push(location)
: 要导航到不同的URL,则使用router.push
方法。该方法会向history
栈添加一个新的记录,当用户单击浏览器的后退按钮时,回到之前的URL。
```js
router.push('/goods') // 字符串
router.push({path: '/goods'}) // 对象
// 自定义网址,携带查询参数
router.push({ path: "/goods", query: { id: 1 } }) // -> /goods?id=1
// 命名路由,携带params参数(废弃,详情查看官网)
router.push({ name: "goods", params: { id: 1 } }) // -> /goods/1
### router.replace
>`router.replace(location)`: ***`router.replace`与`router.push`很像,唯一的不同是它不会向`history`栈添加新记录,而是跟它的方法名一样只替换掉当前的history 记录。***`router.replace(...)`等价于`<router-link :to="..." replace>`。
```js
router.replace('/goods') // 字符串
router.replace({path: '/goods'}) // 对象
// 自定义网址,携带查询参数
router.replace({ path: "/goods", query: { id: 1 } }) // -> /goods?id=1
// 命名路由,携带params参数(废弃)
router.replace({ name: "goods", params: { id: 1 } }) // -> /goods/1
router.go
router.go(n)
: 参数是一个整数,表示在history
记录中向前进多少步或向后退多少步
// 在浏览器记录中前进一步,等同于history.forward()
router.go(1)
// 后退一步,等同于history.back()
router.go(-1)
// 前进三步
router.go(3)
// 如果history记录不够,就会失败
router.go(-100)
router.go(100)
2. 路由对象属性
route
是一个跳转的路由对象,每一个路由都会有一个route
对象,是一个局部的对象,可以获取对应的name
,path
,params
,query
等
$route.path
$route.path
: 字符串,对应当前路由的路径,总是解析为绝对路径,如"/goods"
var current_url = this.$route.path
console.log(current_url)
$route.params
$route.params
: 一个key/value
对象, 包含了动态片段和全匹配片段,如果没有路由参数,就为空对象。
var params = this.$route.params
console.log(params)
$route.query
$route.query
: 一个key/value
对象, 表示URL查询参数。
例如: 对于路径/goods?cate_id=1
,则有$route.query.cate_id == 1
;如果没有查询参数,则为空对象
var query = this.$route.query
console.log(query)
$route.fullPath
$route.ful1Path
: 完成解析后的URL,包含查询参数和hash的完整路径。
var ful1Path = this.$route.ful1Path
console.log(ful1Path)
3. 路由钩子
路由钩子的介绍和案例讲解
全局路由钩子:
router.beforeEach
注册一个全局前置守卫我们可以直接在路由配置文件(/src/main.js)中写钩子函数,但是在路由文件中我们只能写一个。
router.beforeEach((to, from, next) => {
//会在任意路由跳转前执行,next一定要记着执行,不然路由不能跳转了
console.log('beforeEach')
console.log(to,from)
//
next()
})
//
router.afterEach((to, from) => {
//会在任意路由跳转后执行
console.log('afterEach')
})
上述代码中的三个参数:
to
:路由将要跳转的路径信息,信息是包含在对像里边的。from
:路径跳转前的路径信息,也是一个对象的形式。next
:路由的控制参数,常用的有next(true)
和next(false)
。
写在模板中的钩子函数
在配置文件中的钩子函数,只有一个钩子-beforeEnter,如果我们写在模板中就可以有两个钩子函数可以使用:
beforeRouteEnter
:在路由进入前的钩子函数。beforeRouteLeave
:在路由离开前的钩子函数。
<script>
export default {
name: 'params',
data () {
return {
msg: 'params page'
}
},
beforeRouteEnter:(to,from,next)=>{
console.log("准备进入路由模板");
next();
},
beforeRouteLeave: (to, from, next) => {
console.log("准备离开路由模板");
next();
}
}
</script>
这是我们写在params.vue模板里的路由钩子函数。它可以监控到路由的进入和路由的离开,也可以轻易的读出to和from的值。