学习内容
- 单文件组件
- scoped 属性
- 父子嵌套组件应用
- vscode 安装扩展
- 父给子传值
- this 是谁
- render 方法扩展使用
- SPA
- 路由
- 介绍
- 安装
- 子路由
- 路由传参(动态路由)
- 编程式导航
- 路由守卫
- 强制登录思路
单文件组件
把一个组件的全部内容汇合到一个文件中,文件名字是以
.vue
结尾的就称作vue单文件组件
- 普通组件的缺点:普通vue组件 其代码 和 其它JS代码逻辑掺杂在一块儿,不易维护,优势没有发挥到极致!
创建一个简单的单文件组件
- 通过 vuecli 创建一个空的项目并运行
- 创建单文件组件 src/components/01-第一个单文件组件.vue文件,内容如下:
<template> <div> <p>今天是个好日子</p> </div> </template> <script> </script> <style> </style>
- src/main.js文件 导入、注册 组件,内容如下:
import Vue from 'vue/dist/vue.common.js' // Vue实例没有render要使用该vue // import Vue from 'vue' // Vue实例有render要使用该vue(vue.runtime.common.js) // es6模块化导入单文件组件-默认方式 // import 组件模块 from './components/01-第一个单文件组件.vue' import ComOne from './components/01-第一个单文件组件.vue' Vue.config.productionTip = false new Vue({ // 把导入进来的组件给注册好 // components:{组件名称:{配置对象成员}} // 普通组件 // components:{组件名称:组件模块} // 单文件组件 // 组件名称推荐是“xx-yy”格式 components:{ 'com-one':ComOne }, data:{ msg:'开始学习Vue单文件组件' } }).$mount('#app')
- 注意:
- vue 要引入 vue.common.js
- import App 的内容要去除
- Vue 实例内部 render 去除
- 注意:
- public/index.html 文件使用单文件组件
<div id="app">
{{msg}}
<com-one></com-one>
</div>
- 注意:
- 单文件组件的模板内容必须通过template实现,内部要求有唯一根元素
- 单文件组件文件本身比较特殊,必须借助vuecli脚手架项目才可以运行
组织结构
- 构成如下:
- 一个单文件组件涉及有如下3部分:
- template标签,内部要求有唯一根元素(推荐div),template是html5标签,只运行,浏览器源代码不显示
- script标签:该标签内部可以执行普通js代码,但是最主要的是内部可以通过export default {} 导出一个对象,该对象的成员完全可以参考 Vue实例,类似 data、methods、created、filters、components等等都可以应用,各个成员都是为template模板服务的
- style标签:设置css样式,作用给template内部的html标签使用
私有/全局组件的注册
- 在 main.js 中引入单文件组件
- 私有注册:在 new Vue() 中使用私有设置的方式,把组件引入进去
- 全局注册:在 new Vue() 之前使用
Vue.component(组件名称, 组件模块)
,方式注册全局单文件组件
scoped 属性
默认情况下,vue单文件组件的style样式是全局的,如果在一个应用中使用了多个单文件组件,它们使用相同选择器为相同的元素设置了style样式,那么只有一个会起作用 (后者会覆盖前者)
- 作用:使得style的样式针对自己组件生效
- 原理:给每个style标签都设置一个
scoped
属性,这样组件的各个html标签解析出来后都会带有一个与其他单组件标签不同的 data-v-xxx 的唯一属性名称,style样式设定也会自动与这个的data-v-xxx联系起来,这样就使得style样式只针对自己的组件起作用了 - 语法:
<style scoped> .... </style>
- 父子嵌套组件应用: 一个组件里使用另一个组件
<template> <!-- 父组件内容 -->
<div>
<p>father</p>
<my-son></my-son> <!-- 子组件 -->
</div>
</template>
vscode 扩展
安装 Vetur,Vue 2 Snippets 扩展,用于语法高亮,语法提示
- Vue 2 Snippets:设置代码片段,vscode 默认不能给 vue 文件做代码片段设置,需要安装此扩展。
- 设置 -> user snippets -> vue.json,设置如下内容:
{ "Create vue template": { "prefix": "vuec", "body": [ "<template>", " <div>$1</div>", "</template>", "", "<script>", " export default {", "}", "</script>", "", "<style lang=\"less\" scoped>", "</style>", "", ], "description": "Create vue template" } }
在 vue 文件中通过 "vuec" 代码片段创建组件结构内容
- 设置 -> user snippets -> vue.json,设置如下内容:
父给子传值
父组件可以 引入、使用 子组件,从业务上看,该父组件有可能对子组件有个性化需求,为了体现组件的灵活多变,可以通过传值实现
- 语法:
<子组件标签 name=value name=value name=value></子组件标签>
- 子组件接收并应用值,具体通过props接收
<!--在模板中应用传递来的数据--> <input :style="{color:xx}"> <script> export default { // 通过props接收父传递过来的数据,注意各个名称需要使用单引号圈选 props:['xx','xx','xx'] } </script>
this 指向与 render 方法扩展使用
- Vue实例内部指向 new Vue()
- 组件内部指向组件实例(VueComponent),同时该VueComponent有继承Vue,因此组件内部使用this与Vue实例的用法完全一致,即组件内部this可以正常访问自己的data、methods、computed等成员
- render 语法
new Vue({ render:h=>h('p','ok') // 要生成 <p>ok</p> 并覆盖渲染 div容器 render:h=>h(组件模块) // 要使用一个组件模块 对 div容器 进行覆盖渲染 })
- 真实项目中一般喜欢创建一个名称为App.vue的组件,并用它去渲染覆盖 div容器
- 所有业务逻辑实现都从App.vue开始,div容器 就是一个空壳摆设
- 通过render对App.vue组件覆盖渲染应用,所有业务通过App.vue展开:
- 在main.js文件中,要使用默认的vue import Vue from 'vue'
- 所有业务组件都通过App.vue文件做应用( 组件的引入、注册、使用)
SPA
概念定义:SPA英文全称是Single Page Application, 中文翻译是 “单页面应用程序项目”,通俗的理解是:一个网站只有一个Web页面;网站的所有功能都在这个唯一的页面上进行展示与使用
- 好处:
- 实现了前后端分离模式(目前最好的开发模式)开发,各司其职;提高了开发效率;
- 用户体验好,页面部分内容发生变化只需要更新局部即可(非刷新整个页面);
- 缺点:
- 对SEO(搜索引擎)不是很友好,网站从开始到结束始终访问一个程序文件,造成搜索引擎不给检索, 但是有解决方案,再者后台系统应用本身对seo不做要求
- 每次应用运行时,需要一次性把全部的html、js、css等内容加载进来,因此会造成页面一开始请求速度较慢的问题(首页较慢,后续页面正常)
- spa 应用场合:
后台管理系统 和 移动端项目,它们特点是供访问的页面总数量小于500个
路由
路由是一个js功能模块,用于解决做个组件切换显示问题的,本身对组件切换的各个底层技术有做封装,是更成熟组件切换解决方案,使用起来更高级、方便。路由封装的元素有:#锚点超链接、component占位符标签、window.onhashchange、window.location.hash等等
安装路由
- 安装路由两种方式:
- vuecli 创建想项目的时候选择路由
- 单独安装
- 指令:
yarn add vue-router
依赖包:通过npm i 或 yarn add 装的东西就是依赖包,每个依赖包内部有多个功能模块
模块:一个js文件内部有做"模块化导出"动作,这个js文件就是一个(功能)模块
yarn add 依赖包
npm install 依赖包
使用路由
-
配置使用路由的基本步骤:
- 打开 src/main.js
- import 引入路由
- Vue.use(路由模块) 注册路由组件
- 创建路由对象,通过 path、component 设置#锚点与组件的联系
- 在 Vue 实例内部挂载 router 路由对象
-
设置切换按钮和占位符
- 按钮:
<router-link to="/home">首页</router-link> <router-link to="/user">会员</router-link> <router-link to="/movie">电影</router-link>
路由中通过 router-link 设置按钮和#锚点信息
- 占位符:
<router-view></router-view>
路由中通过 router-view 设置组件显示占位符
- 按钮:
-
执行过程:
- 用户点击 页面的 路由链接router-link,点击的一瞬间,就会修改 浏览器 地址栏 中的 #号 锚点地址信息
- #锚点变化了 会立即被 路由 监听到 (路由有封装onhashchange事件)
- 之后 路由 会获取变化后的#锚点信息 (路由有封装window.location.hash)
- 再之后 路由 根据#锚点信息找到对应 的组件 (在main.js中可知)
- 最后组件是通过路由占位符rouer-view显示的
-
重定向:
使得一个路由地址A与另一个路由地址B联系起来,执行A的时候会跳转执行B
- 语法:
var router = new VueRouter({ routes:[ // {path:'/', redirect:'跳转到的路由锚点信息'} {path:'/', redirect:'/home'}, {path:'/home', component:Home}, …… ] })
- 注意:
- 不仅 "/" 可以被重定向配置,其他的普通路由锚点信息也可以设置
- 重定向会使得路由再次发生调用请求
-
router-link-exact-active:
- 路由严格匹配时才会有这个 class 属性,模糊匹配时该信息就没有了。
子路由
一般项目开发中,App.vue是根基组件(第1级别的),内部可以有具体业务组件(Home.vue Movie.vue Music.vue,它们是第2级别的),根据业务需要,业务组件内部还要做内容分级显示,这样就形成第3级别的业务组件,第3级别组件(香港音乐/台湾音乐/大陆音乐)的路由 是 第2级别组件路由 的子路由
- 引入子路由的代码示例:
…… // 引入第3级别业务组件 import Hongkong from './components/yinyue/Hongkong' import Taiwan from './components/yinyue/Taiwan' import Dalu from './components/yinyue/Dalu' …… var router = new VueRouter({ routes: [ { path: '/', redirect: '/hm' }, { path: '/hm', component: Home }, { path: '/mv', component: Movie }, { path: '/ms', component: Music, children: [ // 给Music创建子路由 { path: '/ms/hk', component: Hongkong }, { path: '/ms/tw', component: Taiwan }, { path: '/ms/du', component: Dalu } ] } ] })
- 注意:
- 要通过 children 关键字设置子路由
- 第三级别组件对应的 切换按钮(router-link) 和 显示占位符(router-view) 需要在对应的第二级别组件Music.vue中设置
- 第二级别组件对应的 切换按钮(router-link) 和 显示占位符(router-view) 需要在App.vue组件中设置
路由传参(动态路由)
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个
User
组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在vue-router
的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果
- 声明路由参数:
{ path: '/dt/:xx/:yy/:zz', component: Detail }
- 接收路由参数:
<标签>{{$route.params.xxx}}</标签> <script> new Vue({ this.$route.params.xxx }) </script>
- 注意:
- 路由有参数,那么应用中要传递该参数
- router-link 标签默认被编译为超链接 a 标签,可以设置 tag 属性,使其变为其他标签
编程式导航
一个路由被执行的过程就是一次导航
- 导航种类:
- 声明式导航:router-link 可以编译生成超链接按钮,单击按钮就切换路由并显示对应的组件,这个过程称为"声明式导航(静态)"
- 编程式导航:有时由于业务需要,一个路由被切换执行并不方便通过声明式导航实现,相反是要通过程序代码的方式给实现出来,就是“编程式导航(动态)”
- 编程式导航:
路由对象.push(锚点信息) // 根据锚点执行指定的路由,最经常使用
路由对象.back() // 后退
路由对象.forward() // 前进
路由对象.go(数字整数) // 根据"整形数字"参数做路由的,前进(大于0)、刷新(等于0)、后退(小于0)操作
// 与 BOM 浏览器对象相似
window.history.go()
window.history.back()
window.history.forward()
- 路由对象:
- main.js 中,就是 router
- 在组件实例中就是 this.$router
路由守卫
每个路由在执行的时候都会经历一些“关卡”关卡可以做决定是否继续前进或执行其他路由或停止当前路由执行,关卡就是守卫,守卫有着一夫当关,万夫莫开的作用。
- 使用场景:每个项目都要使用守卫,例如后台管理系统,很多组件页面要求只有处于登录状态(token)的用户才可以访问,判断是否登录就是通过守卫做的
- 语法:
router.beforeEach((to,from,next)=>{code})
- router 是 new VueRouter() 得到的路由对象
- to:是一个对象,保存这将要访问的路由相关参数
- from:是一个对象,保存着离开的那个路由的相关参数
- next:是一个回调函数,对后续的执行起着拦截或放行的作用,如果没有问题一定要执行**next()**方法,以进行后续操作,next()方法也可以通过传递路由信息实现其他组件的显示,例如,next('/login') 显示登陆组件,next(false) 停止当前路由执行
强制登录思路
主要思路:守卫 + sessionStorage + 路由 + 编程式导航
- 保持用户登录状态:
实际项目中:用户输入用户名、密码后,该账号信息需要给到服务器端做校验,校验成功 后台系统会给客户端浏览器传递一个秘钥信息 token [学员胸牌],表明当前账号已经登录系统,请客户端浏览器把token保存起来,后期每次向服务器端发起请求的时候,都要把这个token带着,以便服务器端识别当前账号ok的,因此浏览器中有token就是登录状态,没有就是退出状态