组件化开发
NPM使用
npm简介
- NPM(Node Package Manager)是一个NodeJS包管理和分发工具。
- NPM以其优秀的依赖管理机制和庞大的用户群体,目前已经发展成为整个JS领域的依赖管理工具
- NPM最常见的用法就是用于安装和更新依赖。要使用NPM,首先要安装Node工具。
nodeJS安装
- Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境。
- Node中包含了NPM包管理工具。
- 下载地址:https://nodejs.org/zh-cn/
npm使用
Vue Cli 使用
- Vue CLI是Vue官方提供的构建工具,通常称为脚手架。
- 用于快速搭建一个带有热重载(在代码修改后不必刷新页面即可呈现修改后的效果)及构建生产版本等功能的单页面应用。
- Vue CLI基于 webpack 构建,也可以通过项目内的配置文件进行配置。
- 安装:npm install -g @vue/cli
组件化开发
- 组件(Component)是Vue.js最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。
- Vue的组件系统允许我们使用小型、独立和通常可复用的组件构建大型应用。
组件构成
- Vue 中规定组件的后缀名是 .vue
- 每个 .vue 组件都由 3 部分构成,分别是
- template,组件的模板结构,可以包含HTML标签及其他的组件
- script,组件的 JavaScript 代码
- style,组件的样式
解决eslint报错
module.exports = { root: true, env: { node: true }, extends: [ 'plugin:vue/essential', 'eslint:recommended' ], parserOptions: { parser: '@babel/eslint-parser' }, rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 在rules中添加自定义规则 // 关闭组件命名规则 'vue/multi-word-component-names': 'off' }, overrides: [ { files: [ '**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)' ], env: { jest: true } } ] }
第三方组件
组件间的传值
- 组件可以由内部的Data提供数据,也可以由父组件通过prop的方式传值。
- 兄弟组件之间可以通过Vuex等统一数据源提供数据共享。
Demo
<template> <div id="app"> <Movie v-for="movie in movies" :key="movie.id" :title="movie.title" :rating="movie.rating" ></Movie> <Hello></Hello> </div> </template> <script> import Movie from "./components/Movie.vue"; import Hello from "./components/Hello.vue"; export default { name: "App", data: function () { return { movies: [ { id: 1, title: "金刚狼", rating: 8.7 }, { id: 2, title: "雷神", rating: 7.6 }, { id: 3, title: "蜘蛛侠", rating: 8.9 }, ], }; }, components: { Movie, Hello, }, }; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
components/Movie.vue
<template> <div> <h1>{{title}}</h1> <span>{{rating}}</span> <button @click="fun">点击收藏</button> </div> </template> <script> export default { name:"Movie", props: ["title", "rating"], data: function(){ return { } }, methods: { fun(){ alert("收藏成功") } } } </script>
components/Hello.vue
<template> <h3>hello</h3> </template>
element-ui介绍
- Element是国内饿了么公司提供的一套开源前端框架,简洁优雅,提供了Vue、React、Angular等多个版本。
- 文档地址:https://element.eleme.cn/#/zh-CN/
组件的使用
- 安装:npm i element-ui
- 引入 Element:
图标的使用
- 由于Element UI提供的字体图符较少,一般会采用其他图表库,如著名的Font Awesome
- Font Awesome提供了675个可缩放的矢量图标,可以使用CSS所提供的所有特性对它们进行更改,包括大小、颜色、阴影或者其他任何支持的效果。
- 文档地址:http://fontawesome.dashgame.com/
- 安装:npm install font-awesome
- 使用:import 'font-awesome/css/font-awesome.min.css'
Axios网络请求
Axios的使用
Axios简介
- 在实际项目开发中,前端页面所需要的数据往往需要从服务器端获取,这必然涉及与服务器的通信。
- Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。
- Axios 在浏览器端使用XMLHttpRequests发送网络请求,并能自动完成JSON数据的转换 。
- 安装:npm install axios
- 地址:https://www.axios-http.cn/
发送网络请求
发送get请求
发送post请求
异步回调问题
async/await
其他请求方式
参考:https://axios-http.com/zh/docs/req_config
与Vue整合
- 在实际项目开发中,几乎每个组件中都会用到 axios 发起数据请求。此时会遇到如下两个问题:
- 每个组件中都需要导入 axios
- 每次发请求都需要填写完整的请求路径
- 可以通过全局配置的方式解决上述问题:
跨域
为什么会出现跨域问题
- 为了保证浏览器的安全,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源,称为同源策略,同源策略是浏览器安全的基石
- 同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能
- 所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
- 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域,此时无法读取非同源网页的 Cookie,无法向非同源地址发送 AJAX 请求
跨域问题解决
- CORS(Cross-Origin Resource Sharing)是由W3C制定的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求。
- CORS可以在不破坏即有规则的情况下,通过后端服务器实现CORS接口,从而实现跨域通信。
- CORS将请求分为两类:简单请求和非简单请求,分别对跨域通信提供了支持。
简单请求
满足以下条件的请求即为简单请求:
- 请求方法:GET、POST、HEAD
- 除了以下的请求头字段之外,没有自定义的请求头:
- Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type
- Content-Type的值只有以下三种:
- text/plain、multipart/form-data、application/x-www-form-urlencoded
简单请求的服务器处理
对于简单请求,CORS的策略是请求时在请求头中增加一个Origin字段,
服务器收到请求后,根据该字段判断是否允许该请求访问,如果允许,则在HTTP头信息中添加Access-Control-Allow-Origin字段。
非简单请求
- 对于非简单请求的跨源请求,浏览器会在真实请求发出前增加一次OPTION请求,称为预检请求(preflight request)
- 预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到HTTP头信息字段中,询问服务器是否允许这样的操作。
- 例如一个GET请求:
- Access-Control-Request-Method表示请求使用的HTTP方法,Access-Control-Request-Headers包含请求的自定义头字段
- 服务器收到请求时,需要分别对Origin、Access-Control-Request-Method、Access-Control-Request-Headers进行验证,验证通过后,会在返回HTTP头信息中添加:
- Access-Control-Allow-Methods、Access-Control-Allow-Headers:真实请求允许的方法、允许使用的字段
- Access-Control-Allow-Credentials: 是否允许用户发送、处理cookie
- Access-Control-Max-Age: 预检请求的有效期,单位为秒,有效期内不会重复发送预检请求。
- 当预检请求通过后,浏览器才会发送真实请求到服务器。这样就实现了跨域资源的请求访问。
- 在传统的Java EE开发中,可以通过过滤器统一配置,而Spring Boot中对此则提供了更加简洁的解决方案
前端路由管理
Vue Router 的安装及使用
- Vue路由vue-router是官方的路由插件,能够轻松的管理 SPA 项目中组件的切换。
- Vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来
- vue-router 目前有 3.x 的版本和 4.x 的版本,vue-router 3.x 只能结合 vue2 进行使用,vue-router 4.x 只能结合 vue3 进行使用
- 安装:npm install vue-router@4
一. 路由(Vue2)
1. SPA 与前端路由
路由是根据不同的url地址来显示不同的页面或内容的功能,这个概念很早是由后端提出的,既浏览器向不同的地址发送请求,后端返回相应的内容。
SPA 指的是一个 web 网站只有唯一的一个 HTML 页面,所有组件的展示与切换都在这唯一的一个页面内完成。此时,不同组件之间的切换需要通过前端路由来实现。
前端路由通常是通过监听URL hash属性值的变化,切换页面,hash 属性是一个可读可写的字符串
,该字符串是 URL 的锚部分(从 # 号开始的部分)。
前端路由的工作方式
前端路由,指的是 Hash 地址与组件之间的对应关系。
- 用户点击了页面上的路由链接
- 导致了 URL 地址栏中的 Hash 值发生了变化
- 前端路由监听了到 Hash 地址的变化
- 前端路由把当前 Hash 地址对应的组件渲染都浏览器中
2. vue-router基本使用
vue-router 是 vue.js 官方给出的路由解决方案。它只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换。
vue-router 目前有 3.x 的版本和 4.x 的版本。其中:
- vue-router 3.x 只能结合 vue2 进行使用
- vue-router 4.x 只能结合 vue3 进行使用
官方文档:https://router.vuejs.org/zh/installation.html
vue-router的基本使用步骤:
- 在项目中安装 vue-router
- 定义路由组件
- 声明路由链接和占位符
- 创建路由模块
- 导入并挂载路由模块
vue-router安装
npm install vue-router@3
创建路由组件
在项目中定义 Discover.vue、Friends.vue、My.vue 三个组件,将来要使用 vue-router 来控制它们的展示与切换:
Discover.vue:
<template> <div> <h1>发现音乐</h1> </div> </template>
Friends.vue:
<template> <div> <h1>关注</h1> </div> </template>
My.vue:
<template> <div> <h1>我的音乐</h1> </div> </template>
声明路由链接和占位标签
可以使用 标签来声明路由链接,并使用 标签来声明路由占位符。示例代码如下:
App.vue:
<template> <div> <h1>APP组件</h1> <!-- 声明路由链接 --> <router-link to="/discover">发现音乐</router-link> <router-link to="/my">我的音乐</router-link> <router-link to="/friend">关注</router-link> <!-- 声明路由占位标签 --> <router-view></router-view> </div> </template>
创建路由模块
在项目中创建 index.js 路由模块,加入以下代码:
import VueRouter from 'vue-router' import Vue from 'vue' import Discover from '@/components/Discover.vue' import Friends from '@/components/Friends.vue' import My from '@/components/My.vue' //将VueRouter设置为Vue的插件 Vue.use(VueRouter) const router = new VueRouter({ // 指定hash属性与组件的对应关系 routes: [ { path: '/discover', component: Discover }, { path: '/friends', component: Friends }, { path: '/my', component: My }, ] }) export default router
挂载路由模块
在main.js中导入并挂载router
import Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({ render: h => h(App), router:router }).$mount('#app')
3. vue-router进阶
路由重定向
路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面。
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
const router = new VueRouter({ // 指定hash属性与组件的对应关系 routes: [ // 当用户访问 / 时,跳转到 /discover { path: '/', redirect: '/discover'}, { path: '/discover', component: Discover }, { path: '/friends', component: Friends }, { path: '/my', component: My }, ] })
嵌套路由
在 Discover.vue 组件中,声明 toplist和 playlist的子路由链接以及子路由占位符。示例代码如下:
<template> <div> <h1>发现音乐</h1> <!-- 子路由链接 --> <router-link to="/discover/toplist">推荐</router-link> <router-link to="/discover/playlist">歌单</router-link> <hr> <router-view></router-view> </div> </template>
在 src/router/index.js 路由模块中,导入需要的组件,并使用 children 属性声明子路由规则:
const router = new VueRouter({ // 指定hash属性与组件的对应关系 routes: [ { path: '/', redirect: '/discover'}, { path: '/discover', component: Discover, // 通过children属性,嵌套声明子路由 children: [ {path:"toplist",component:TopList}, {path:"playlist",component:PlayList}, ] }, { path: '/friends', component: Friends }, { path: '/my', component: My }, ] })
动态路由
思考:有如下 3 个路由链接:
<router-link to="/product/1">商品1</router-link> <router-link to="/product/2">商品2</router-link> <router-link to="/product/3">商品3</router-link>
const router = new VueRouter({ // 指定hash属性与组件的对应关系 routes: [ { path: '/product/1', component: Product }, { path: '/product/2', component: Product }, { path: '/product/3', component: Product }, ] })
上述方式复用性非常差。
动态路由指的是:把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在 vue-router 中使用英文的冒号(:)来定义路由的参数项。示例代码如下:
const router = new VueRouter({ // 指定hash属性与组件的对应关系 routes: [ { path: '/product/1', component: Product }, { path: '/product/2', component: Product }, { path: '/product/3', component: Product }, ] })
通过动态路由匹配的方式渲染出来的组件中,可以使用 $route.params 对象访问到动态匹配的参数值,比如在商品详情组件的内部,根据id值,请求不同的商品数据。
<template> <h1>Product组件</h1> <!-- 获取动态的id值 --> <p>{{$route.params.id}}</p> </template> <script> export default { // 组件的名称 name: 'Product' } </script>
为了简化路由参数的获取形式,vue-router 允许在路由规则中开启 props 传参。示例代码如下:
{ path: '/product/:id',component: Product, props: true }
<template> <h1>Product组件</h1> <!-- 获取动态的id值 --> <p>{{id}}</p> </template> <script> export default { // 组件的名称 name: 'Product', props : [id] } </script>
编程式导航
声明式 |
编程式 |
|
|
除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
想要导航到不同的 URL,则使用 router.push
方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(...)
。
<template> <button @click="gotoProduct(2)">跳转到商品2</button> </template> <script> export default { methods:{ gotoProduct: function(id){ this.$router.push('/movie/${id}') } } } </script>
导航守卫
导航守卫可以控制路由的访问权限。示意图如下:
全局导航守卫会拦截每个路由规则,从而对每个路由进行访问权限的控制。
你可以使用 router.beforeEach
注册一个全局前置守卫:
router.beforeEach((to, from, next) => { if (to.path === '/main' && !isAuthenticated) { next('/login') } else { next() } })
to
: 即将要进入的目标from
: 当前导航正要离开的路由- 在守卫方法中如果声明了 next 形参,则必须调用 next() 函数,否则不允许用户访问任何一个路由!
- 直接放行:next()
- 强制其停留在当前页面:next(false)
- 强制其跳转到登录页面:next('/login')