Vue.js的发展
前端发展的行业非常快,大部分学习者赶不上发展的速度,每天都在学习Google的AngularJS,Fackbook的ReactJS,这些前端MVC(MVVM)框架和组件化学习,加上Vue.js的出现,越来越多的前端投入了学习中。
一. Vue基础
认识Vue.js
Vue是一个渐进式的框架
渐进式意味着你可以将Vue作为你应用的一部分嵌套其中
Vue的核心库以及其生态系统
Core + Vue-router + Vuex
Vue特点和Web开发常见高级功能
解耦视图和数据
可复用的组件
前端路由技术
状态管理
虚拟DOM
Vue安装方式
方式一. 直接CDN引入
可以选择引入开发环境版本 / 生产环境版本
// 开发环境版本, 包含了帮助的命令行警告
<srcipt src='https://cdn.jsdeliver.net/npm/vue/dist/vue.js'></script>
// 生产环境版本, 优化了尺寸和速度
<srcipt src='https://cdn.jsdeliver.net/npm/vue'></script>
方式二. 下载和引入
// 开发环境
https://vuejs.org/js/vue.js
// 生产环境
https://vuejs.org/js/vue.min.js
方式三. NPM安装
通过webpack和CLI的使用
Vue的MVVM
M: Model 数据模型
- 数据层
- 数据可能是固定的思数据, 更多的是来自服务器, 从网络上请求下来的数据
V: View 视图模板
- 视觉层
- 在前端开发中, 通常是DOM层
- 作用: 是给用户展示各种信息
VM:View-Model 视图模型
- 视图模型层
- 是View和Model沟通的桥梁
- 一方面实现了Data Binding (数据绑定), 讲Model的改变实时的反应到View中
- 另一方面实现了DOM Listener (DOM监听), 当DOM发生一些时间 (点击, 滚动, touch等) 时, 可以监听到, 并在需要的情况下改变对应的Data
二. Vue基础语法
语法
插值操作 Mustache
- Mustache语法 (双大括号)
- 可以直接写变量
- 可以写简单的表达式
v-once
- 后面不需要跟任何表达式
- 表示元素和组件只渲染一次, 不会随着数据的改变而变化
v-html
- 后面往往跟一个string类型
- 会将string的html解析出来并渲染
v-text
与Mustache相似, 一般不用, 不灵活
v-pre
用于跳过这个元素和它子元素的编译过程, 用于显示原本的Mustache语法
v-cloak
在某些情况下, 我们浏览器可能会直接显示出未编译的Mustache标签
v-bind
作用: 动态绑定属性
简写: :
条件判断
- v-if
- v-else-if
- v-else
- v-show
当条件为false的时
- v-if: 指令的元素, 不会渲染到dom中
- v-show: dom增加一个行内样式display: none
v-on
作用: 绑定事件监听
简写: @
写法:
- 没有参数的情况下, 可以不写(); 如果方法本身有一个参数, 会默认将原生事件event参数传递进去
- 如果传入某个参数, 同时需要event时, 可以通过$event传入时间。
.stop
阻止事件冒泡
event.stopPropagation()
.prevent
阻止默认事件
event.preventDefault()
.native
监听组件根元素的原生事件
.once
只触发一次回调
修饰符
lazy修饰符
- 前景: v-model默认是在input事件中实时同步输入框的数据的 (容易同步的过于频繁 )
- 作用: 可以让数据只有在失去焦点或回车时才会更新
number修饰符
- 前景: 默认情况下, 在输入框中无论输入字母还是数字, 都会被当做字符串类型进行处理
- 作用: 当做数字类型进行处理
trim修饰符
- 前景: 输入的内容首位容易有空格
- 作用: 可以过滤掉内容左右两边的空格
computed / methods区别
多次使用的时候
- methods: 每次都会调用
- computed: 计算机会缓存, 不变的情况下只调用一次
fulters过滤器
<div id='app'>
<h2 {{aaa | showA}}></h2>
</div>
const app = new Vue({
el: '#app',
data:{
aaa: 'li'
},
// 过滤器
fulters: {
showA (value) {
return;
}
})
三. 组件通讯
父子组件的通讯
- 父组件通过props向子组件传递数据
- 子组件通过事件向父组件发送数据
父组件访问子组件
- $children: 拿所有子组件
- $refs: 拿指定的子组件
// this.$children是一个数组类型, 它包含所有子组件对象
// 通过遍历, 取出所有子组件的message状态
// 使用$refs的时候, 在想要访问的子组件上添加ref属性
子组件访问父组件
- $parent: 上一级父组件
- $root: 根组件
四. 插槽slot
组件的插槽是为了让我们封装的组件更加具有扩展性
让使用者可以决定组件内部的一些内容到底展示什么
基本使用
- 插槽的基本使用
- 插槽的默认值 button
- 如果有多个值同时放入到组件进行替换时, 一起作为替换元素
具名插槽
在多个插槽的情况下, 替换制定插槽的内容
<div id="app">
<cpm></cpn>
<cpm><button slot="left">返回</button></cpn>
<cpm><span slot="center">中间标题</span></cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
const app = new Vue({
el: '#app',
data: {
meassage: '哈哈哈'
},
components: {
cpn: {
template: '#cpn'
}
}
})
作用域插槽
编译作用域
父组件模板所有的东西都在父级作用域内编译, 子组件模板的所有东西会在子级作用域内编译
<div id="app">
<cpm v-show="isShow">我是一</cpn> // true
</div>
<template id="cpn">
<div>
<p v-show="isShow">我是二</p> // false
</div>
</template>
const app = new Vue({
el: '#app',
data: {
isShow: true // Vue实例中的属性
},
components: {
cpn: {
template: '#cpn',
data() {
return {
isShow: false // 子组件中的属性
}
}
}
}
})
五. vue-router
目前前端流行的三大框架, 都有自己的路由实现:
- Angular: ngRouter
- React: ReactRouter
- Vue: vue-router
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用
我们可以访问其官方网站对其进行学习: router.vuejs.org/zh/
vue-router是基于路由和组件的
路由用于设定访问路径, 将路径和组件映射起来.
在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
vue-router的使用
- : 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签
- : 该标签会根据当前的路径, 动态渲染出不同的组件
- 网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和处于同一个等级
- 在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变
router-link属性补充
属性 to
用于指定跳转的路径
<router-link to='/home'></router-link>
属性 tag
可以指定之后渲染成什么组件
// 会被渲染成一个<li>元素
<router-link to='/home' tag='li'></router-link>
...
属性 replace
不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中
<router-link to='/home' replace></router-link>
属性 active-class
设置active-class可以修改默认的名称
// home被选中状态
// 当<router-link>对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class
<router-link to='/home' router-link-active></router-link>
<router-link to='/about'></router-link>
// 修改默认的名称
<router-link to='/home' active-class="active"></router-link>
<router-link to='/about' active-class="active"></router-link>
...
// 每一个都添加太麻烦了, 可以在router - index.js中统一修改
const app = new VueRouter({
router,
mode: 'history',
linkActiveClass: 'active'
})
路由跳转第二种方法
在路由跳转需要执行对应的js代码的时候, 可以使用
-- App.vue文件
<div>
<router-link @click="linkToHome"></router-link>
<router-link @click="linkToAbout></router-link>
<router-view></router-view>
</div>
<script>
export default {
name: 'App',
methods: {
// Vue-router在所有组件里都加入了$router
linkToHome () {
// push => pushState 可以返回
this.$router.push('./home')
},
linkToAbout () {
// replace => replaceState 没有返回
this.$router.replace('./about')
}
}
}
</script>
vue-router参数传递
传递参数的方式
传递参数主要有两种类型: params和query
vue-router导航守卫
为什么使用导航守卫
我们来考虑一个需求: 在一个SPA应用中, 如何改变网页的标题呢
-
网页标题是通过来显示的, 但SPA只有一个固定的HTML, 切换不同页面时, 标题并不会改变
-
可以通过JS来修改的内容 window.document.title = “新的标题”
更好的办法-使用导航守卫
-
vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
-
vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.
导航守卫使用
我们可以利用beforeEach来完成标题的修改.
首先, 我们可以在钩子当中定义一些标题, 可以利用meta来定义
其次, 利用导航守卫,修改我们的标题.
-- index.js文件
import Vue from ‘vue’
import VueRouter from ‘vue-router’
const Home = () => import('../components/Home.vue')
const User = () => import('../components/User.vue')
Vue.use(VueRouter)
const routes = [
{
path: '/home',
redirect: './home',
// 元数据 (描述数据的数据)
meta: {
title: '首页'
}
},
{
path: '/user',
component: User,
meta: {
title: '用户'
}
}
]
const app = new VueRouter({
router,
mode: 'history'
})
// 前置守卫(guard)
router.beforeEach((to, from, next) => {
// 从from跳转到to
window.document.title = to.matched[0].meta.title;
next();
})
export default router
导航钩子的三个参数解析:
- to: 即将要进入的目标的路由对象
- from: 当前导航即将要离开的路由对象
- next: 调用该方法后, 才能进入下一个钩子
导航守卫补充
- 如果是后置钩子, 也就是afterEach, 不需要主动调用next()函数.
- 上面我们使用的导航守卫, 被称之为全局守卫
路由独享的守卫
组件内的守卫
// 后置守卫(guard)
router.afterEach((to, from) => {
})
六. Vuex详解
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
- 它采用 集中式存储管理 应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能
状态管理到底是什么
- 状态管理模式、集中式存储管理
- 可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面
- 然后将这个对象放在顶层的Vue实例中,让其他组件可以使用
- 那么多个组件是不是就可以共享这个对象中的所有变量属性了呢
管理什么状态呢
如果你做过大型开放,你一定遇到过多个状态,在多个界面间的共享问题。
比如用户的登录状态、用户名称、头像、地理位置信息等等。
比如商品的收藏、购物车中的物品等等。
这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的
Vuex核心概念
state单一状态树
Vuex提出使用单一状态树, 即单一数据源
应用开发中
-
- 如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。
- 所以Vuex也使用了单一状态树来管理应用层级的全部状态。
- 单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护
Getters
类似于computed
需要从store中获取一些state变异后的状态
Mutation
Mutation状态更新
Vuex的store状态的更新唯一方式:提交Mutation
Mutation主要包括两部分
-
- 字符串的事件类型(type)
- 一个回调函数(handler),该回调函数的第一个参数就是state
Mutation定义方式
mutations: {
aaa(state) {
state.xx++
}
}
Mutation传递参数
aaa(state, payload) {
state.count -= payload.count;
}
bbb: function () {
this.$store.commit('aaa', {count: 0});
}
Actions
不要再Mutation中进行异步操作.
Action类似于Mutation, 但是是用来代替Mutation进行异步操作的.
Module
Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理.
当应用变得非常复杂时,store对象就有可能变得相当臃肿.
为了解决这个问题, Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutation、action、getters等