这一路上可能会有艰辛、困难、疑惑、付出、泪水、失败,但是一定要享受这个过程,因为所有的失败都是为了下一刻的成功
文章目录
- 组件
- 什么是组件
- 组件化开发的好处
- 组件底层是什么
- 全局注册组件
- 局部注册组件
- 组件嵌套
- 组件命名规则
- 组件传值
- SPA
- vue-router路由
- 动态路由
- to属性
- 编程式导航
- 重定向
- 导航守卫
- 路由嵌套
组件
什么是组件
- js模块,独立的一个js文件,提供js逻辑,函数
- vue组件,关注于界面,包含html结构、css样式、js代码,他可以把一个完成的页面根据界面功能拆分成若干组件
组件化开发的好处
- 高度复用
- 组件与组件之间是相互独立的,例如:数据、函数,组件实现的功能足够单一,后期更好维护
组件底层是什么
- 组件本质上是一个vue实例,但是写法和vue实例不同,new Vue({配置对象})
- 组件会通过Vue.component(组件)或者在vue实例中new Vue({component:{组件}})
- 组件也有配置对象,不包含el选项,el是Vue实例管理的视图容器,组件通过template选项指定html结构容器
- 配置选项:data、methods、watch、filters、directives、computed、cerated…(创建组件,创建vue实例)
<div id="app">
<com-add></com-add>
</div>
<script src="./vue.js"></script>
<script>
// 注册组件(vue实例)
Vue.component('com-add', {
template: `<div>{{count}} <button @click="add()">自增</button></div>`,
data() {
return {
count: 0
}
},
methods: {
add() {
this.count++
}
}
})
// vue实例
const vm = new Vue({
el: '#app'
})
</script>
全局注册组件
- 语法:
Vue.component('组件名称','组件配置对象')
- 完成注册后,可以在任意Vue实例管理的视图中使用
<div id="app">
<!-- 注册组件的时候使用的组件名称,在视图中使用的是自定义标签的名称 -->
<!-- 注意:组件的名称不能和原声html标签重名 -->
<com-add></com-add>
</div>
<script src="./vue.js"></script>
<script>
// 全局注册组件
Vue.component('com-add', {
// 组件配置对象,和vue实例配置对象基本一致,但是没有el选项
// template选项必须指定,当前组件管理的视图,需要有一个根标签
// 在模板字符中,可以使用插值表达式和任意指令,但是只能使用当前组件数据和函数
template: '<div>{{count}}<button @click="add()">自增1</button></div>',
// 声明数据,使用的还是data,但是如果是一个函数,函数的返回值才是组件的数据,必须是对象
data() {
return {
count: 100
}
},
// 可以使用任何配置选项
methods: {
add() {
this.count++
}
}
})
// 根实例
const vm = new Vue({
el: '#app'
})
</script>
局部注册组件
- 语法:
vue配置对象中 components:{'组件名称':'组件配置对象'}
- 注册完毕后,只能在注册的当前vue实例管理的视图中使用
<div id="app">
<com-add></com-add>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
// 配置选项 components 注册局部组件
components: {
// 属性名称:组件的名称
// 属性值:组件的配置对象
'com-add': {
template: '<div>{{count}} <button @click="add()">自增</button></div>',
data() {
return {
count: 100
}
},
methods: {
add() {
this.count++
}
}
}
}
})
</script>
组件嵌套
<div id="app">
<com-a></com-a>
</div>
<script src="./vue.js"></script>
<script>
// b组件配置对象
const ComB = {
template: `<div class="com-b">COMB组件</div>`,
}
// a组件配置对象
const ComA = {
template: `<div class="com-a">COMA组件<com-b></com-b></div>`,
components: {
'com-b': ComB
}
}
// 根实例
const vm = new Vue({
el: '#app',
components: {
'com-a': ComA
}
})
</script>
组件命名规则
- 第一种:小写单词加中线 例如 com-add, nav-bar
- 在使用组件的时候
<com-add></com-add> 、<nav-bar></nav-bar>
- 在使用组件的时候
- 第二种:单词首字母大写 例如 ComAdd、NavBar
- 在使用的时候
<com-add></com-add> , <nav-bar></nav-bar>
- 注意:如果想使用单词首字母大写的组件名称作为标签的名称,只能在template指定的视图中使用
<ComAdd></ComAdd>、<NavBar></NavBar>
,通过el指定的dom容器中不能使用
- 在使用的时候
组件传值
- 由于组件的数据是相互独立的,导致某个组件需要使用另外一个组件的数据遇到问题,我们需要通过特定的进行组件间的数据通信
- 父组件传子组件
总结<div id="app"> <com-parent></com-parent> </div> <script src="./vue.js"></script> <script> // 父组件 Vue.component('com-parent', { template: `<div>父组件: {{msg}}<com-child abc="abc数据" :myMsg="msg"></com-child></div>`, data() { return { msg: 'parent数据' } } }) // 子组件 Vue.component('com-child', { template: `<div>子组件:{{myMsg}}</div>`, // props 用来接收使用组件所绑定的属性,属性的名字就是数据的字段名 // props接收的数据,是单向的,只负责父组件数据传递子组件 // props接收的数据,仅仅只能访问,不能修改 // props['abc']接收到了使用组件绑定的abc属性,使用vue实例即可访问 // 此时的this.myMsg就是父组件传递给子组件的数据 props: ['abc', 'myMsg'] }) // 根实例 const vm = new Vue({ el: '#app' }) </script>
- 在父组件中,使用子组件的时候,通过自定义属性绑定父组件数据
- 在子组件中,使用props选项来接收父组件传递给子组件的数据
- props接收的数据仅仅只能访问,不能修改
- 子组件传父组件
总结<div id="app"> <com-parent></com-parent> </div> <script src="./vue.js"></script> <script> // 父组件 Vue.component('com-parent', { template: `<div>父组件:<com-child @myEvent="fn($event)"></com-child></div>`, methods: { fn(data) { // data就是子组件的数据 console.log('父组件打印:' + data) } } }) // 子组件 Vue.component('com-child', { template: `<div>子组件:<button @click="toParent()">子传父</button></div>`, data() { return { msg: 'child数据' } }, methods: { toParent() { // 子传父 this.$emit('myEvent', this.msg) } } }) const vm = new Vue({ el: '#app' }) </script>
- 在父组件,给子组件绑定自定义事件,会指定函数
- 在子组件,内部使用
this.$emit('自定义事件的名字','传递的数据')
- 在父组件,指定的函数就会触发,而且默认的传参就是传递的数据,
$event
就是传递的数据
- vue实例提供了一个参数,可以出发自己组件绑定的数据
this.$emit('myEvent')
,myEvent就是自定义事件的名字this.$emit('myEvent',数据)
事件对于的函数有一个默认的传参- 指定的函数没有括号fn拥有一个默认传参,就是触发事件的时候传递的数据
- 指定的函数有了括号fn($event),这个event就是触发事件的时候传递的数据
SPA
- 特点介绍
- 单页面应用程序,简称SPA(single page application),大白话就是一个系统上的所有功能在一个页面上实现
- 优点
- 利于实现前后端分离而且是项目及的分离
- 只有资源加载完毕后,场景与场景之间的切换很流畅
- 缺点
- 把所有功能写在一起,一个页面的资源较大,第一次访问紫铜很慢(首屏加载数据慢)
- 在一个页面上实现,数据都是异步加载,js动态渲染,不利于搜索引擎优化
- 路由
- 后端路由
- 根据用户的请求地址+方式,分发到不同的业务函数,进行逻辑处理
- 控制客户端请求和后端处理函数的映射关系
- 前端路由
- 根据地址栏变化(不发请求),根据地址栏的不同局部更新页面内容
- 前端业务场景切换
- 在vue项目中的路由
- 控制地址变化和组件渲染的映射关系
- 根据地址栏变化(不发请求),根据地址栏的不同局部更新页面内容
- 模拟前端路由的视线
<nav> <!-- 地址上的改变 以#号这种方式的改变 是不会发生页面跳转的 --> <!-- 术语:#和#后 这段URL字符串称为:hash地址(锚点) --> <!-- hash的改变也会记录到浏览历史中,通过回退和前进也可以切换业务场景 --> <!-- 前端路由:监听的hash值的改变,去根据地址对应的网页内容 --> <a href="#/">发现音乐</a> <a href="#/my">我的音乐</a> <a href="#/friend">朋友</a> </nav> <div id="content"> <!-- 需要根据地址(hash)来进行渲染 --> </div> <script> // 容器 const content = document.querySelector('#content') const render = () => { // 获取hash地址 const hash = location.hash // 去除#获取hash上的路径 const path = hash.replace('#', '') // 根据路径渲染网页内容 switch (path) { case '/': content.innerHTML = '发现音乐的网页内容' break; case '/my': content.innerHTML = '我的音乐的网页内容' break; case '/friend': content.innerHTML = '朋友的网页内容' break; } } render() // 当hash值变化的时候,动态设置网页内容 window.onhashchange = function () { render() } </script>
- 后端路由
vue-router路由
动态路由
- 适用场景:不同的路由地址,指向同一个组件,此时需要使用动态路由
to属性
- 作用:
<router-link>
组件上的属性to,它的作用是声明点击后的跳转的路由地址 - 使用
- 直接使用字符串,简单路劲跳转
router-link to="/list"></router-link>
- 可以使用字符串,进行路径的跳转
- 路径传参 路由规则{ path: ‘/article/:id’ }
<router-link to="'/article/10001"></router-link>
- 键值对传参 路由规则 { path: ‘/article’ }
<router-link to="'/article?id=10001"></router-link>
- 路径传参 路由规则{ path: ‘/article/:id’ }
- 普通跳转
<router-link :to="{path:'/list'}"></router-link>
- 路径传参
const routes = [{path:'/article/:id',name:'item',component:Articl
<router-link :to="{name:'item',params:{id:10001}}"></router-link>
$route.params.id
#进行获取
- 键值对传参
const routes = [{path:'/article/',component:ArticleItem}]
<router-link :to="{path:'/article',query:{id:1001}}></router-link>
$route.query.id
进行获取
- 直接使用字符串,简单路劲跳转
编程式导航
<router-link>
这个标签可以实现导航功能- 通过显性的组件router-link定义的导航(在界面看的见),声明式导航
- 通过
$router.push()
这个函数可以实现导航功能- 通过js代码调用一个导航函数进行跳转,编程式导航
$route
和$router
的区别- $route是获取当前地址栏信息的对象(参数,地址)
- $route.params 路径参数
- $route.query 键值对参数
- $route.path 路由地址
- $router是路由实例new VueRouter()挂载到vue实例上
- 所有的vue实例,拥有一个属性$router提供函数
- $route是获取当前地址栏信息的对象(参数,地址)
- 使用场景
- 在界面上,有确切的跳转链接,使用声明式导航
- 当在执行一个js逻辑的时候,想进行跳转,此时就用编程式导航
- 在做登录页的时候,登录成功后,才应该跳转到首页
重定向
- 当访问某个地址的时候,经过程序的处理(用户看不到的),跳转到了另外一个地址
- 前端的路由,使用重定向功能
- 访问页面的时候,默认hash地址是 #/, 默认的路由地址 /
- 我们的项目首页/home,所以当我们访问 / 重定向到 /home,才能默认访问首页
- 重定向配置
- 通过路由规则栏实现的,
{path:'/',redirect:'/home'}
当访问路径跳转到/home路径
- 通过路由规则栏实现的,
导航守卫
- 实现在路由跳转前,实现一些业务逻辑,可以控制跳转的最终目标
- 总结
- 导航守卫
router.beforeEach((to, from, next) => {}
- 在每次路由跳转前执行里面的回调函数
- 可以实现前端路由的访问权限控制,登录状态的判断与拦截
- 导航守卫
路由嵌套
- 概念:在已有的路由容器中,再实现一套路由,再套一个路由容器,叫路由嵌套
- 配置:
{path:'/',component:'组件',children:[]}