Vue2
版本:
- vue 2.x
- vue-router 3.0.x
- vue-cli 2.x 3.x
一. Vuejs
MVVM
-
View,视图层(DOM)
-
ViewModel,双向
- View -> DOM Listeners -> Model,DOM监听
- View <- Data Bindings <- Model,数据绑定
-
Model,数据层(数据)
二. Vue基础语法
1. 插值语法
- {{}}
- v-once,只渲染一次,之后不改变
- v-html
- v-text
2.绑定属性
-
v-bind
- v-bind:src="imgUrl"
- :src="imgUrl"
-
绑定class
- :class="{className: boolean}"
- :class="[变量名]"
-
绑定style
- :style="{color: fontColor}"
- :style="[{color: 'lightpink'}]"
3.计算属性
- 数据先处理再显示
- 会进行缓存,多次使用只调用一次
- 若方法的变量变了,会自动调用
4.事件监听
-
v-on:click="plus"@click="plus"绑定事件的监听器 -
参数
@click="btnClick" btnClick (event) {}@click="btnClick('params', $event)" btnClick (params, event) {}- event参数->浏览器生产的 event 事件
-
修饰符
-
.stop
@click.stop="insideBox"阻止 inside 往 outside 冒泡
-
.prevent
- 调用 event.stopPropagation(),阻止标签的默认行为
-
.{keyCode | keyAlias}
@keyup.enter="keyup"监听键盘的某个键值(键修饰符)
-
once
- 只触发第一次回调
-
.native
- 监听组件根元素的原生事件
-
<!-- 父组件 --> <template> <div> <Button text="" icon="" @click.native="onButtonClick" /> </div> </template> <!-- 子组件 --> <template> <button> <sapn>{{text}}</sapn> <i>{{icon}}</i> </button> </template> <!-- 子组件Button内部(span,i)的原生事件,绑定到组件的根元素上,使父组件可以直接监听Button的原生事件-->
-
原生事件和自定义事件
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生事件与自定义事件</title>
</head>
<style>
.boxStyle {
margin: 20px;
border-bottom: 1px solid lightgray;
}
</style>
<body>
<div id="box1" class="boxStyle">
<!-- 原生事件,在子组件上绑定后可直接使用 -->
<my-cpn1 @click.native="onClick"></my-cpn1>
<!-- 自定义事件,在子组件上绑定,要通过子组件的触发$emit才能执行 -->
<my-cpn1 @onclick="onClick"></my-cpn1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const component1 = Vue.extend({
template: `
<div>
<h3 @click="onComponentClick">component</h3>
<span>span11111111111111</span>
</div>
`,
methods: {
onComponentClick() {
console.log('子组件被点击')
this.$emit('onclick')
}
}
})
Vue.component('my-cpn1', component1)
const box1 = new Vue({
el: '#box1',
methods: {
onClick() {
console.log('父组件被点击')
}
}
})
</script>
</body>
</html>
5.条件与循环
-
v-if v-else
-
input切换了,input的值还在
- 基于性能考虑,虚拟DOM在渲染时会尽可能复用存在的元素,给标签加不同的key可避免
- vue2的diff算法
-
-
v-show
v-if 和 v-show
-
v-if 为 false 时,元素不会存在 DOM 中
-
v-show 为 false 时,元素添加行内样式:display: none;
-
显示与隐藏切片频繁时,用 v-show ;只有一次切换时,用 v-if
-
v-for
- 使用时,加上 :key,给每个节点做一个标识,使其更高效的更新虚拟 DOM
v-if 和 v-for
- v-for的优先级高于v-if(vue2),v-if高于v-for(vue3)
- 不用在同一个元素上,避免产生渲染顺序问题和保持代码的可读性和维护性
6.表单绑定
-
v-model
-
语法糖,实际两操作
:value = "message"v-bind 绑定一个 value 属性@input = "message = $event.target.value"v-on 给当前绑定 input 事件
-
7.其他
-
filters
-
// 通过capitalize过滤器对message的值进行格式化 <p>{{ message | capitalize}}</p> const vm = new Vue({ ..., filters: { capitalize(str) { return str.chatAr(0).toUpperCase + str.slice(1) } } })
-
-
watch
-
属性
- immediate
-
watch 和 computed
三、组件化开发
1.组件
-
data属性
data() {return {}}必须是函数,返回一个对象- 保证每个实例对象的 data 是互不干扰的,所以 data 需要返回一个独立的新对象
-
注册组件的基本步骤
- a. 调用 Vue.extend() 方法创建组件构造器
- b. 调用 Vue.component() 方法注册组件
- c. 在 Vue实例的作用范围内使用组件
2.组件间数据传递
-
父级 -> 子级
- props
-
父 <cpn :movies="movies"></cpn> 子 props - 不要直接修改 props,用 data 或者 computed 包一层
- 11
-
子级 -> 父级
- $emit
-
父 <cpn @itemClick="itemClick" /> 子 methods: { btnClick(item) { this.$emit('itemClick', item) } } - 11
-
父组件访问子组件
- this.$children[0],数组对象
- this.$refs.cpn,对象,
子<cpn ref="cpn"></cpn>
-
子组件访问父组件
- this.$parent
- this.$root
-
非父子组件
3.组件化
-
slot
- 匿名插槽
- 具名插槽
- 作用域插槽:子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽
-
动态组件
v-bind:component='cpnName' -
异步组件
() => import( './cpn' )
组件的生命周期
四、Vue CLI
1.模块化开发
-
CommonJS
- 导出:
module.exports = {one: 1, two: 2} - 导入:
let {one, two} = require("./a.js")
- 导出:
-
ES6 的 Modules
- 导出:
export - 导入:
import
- 导出:
2.webpack
- entry、output
- loaders(转化器)
- plugins(扩展器)
3.vue-cli3
4.vue-router
-
前端路由时代
- 整个网站只有一个 html 页面,index.html+css+js(全部)
- 前端管理 URL -> 页面,改变URL,页面不整体刷新(还在同一个网站)
-
前端路由规则
-
浏览器URL的hash
- www.baidu.com/#aaa
- 没有发送请求,只是改变页面位置(锚点)
-
HTML5的history
- www.baidu.com/aaa
- 栈结构,入栈
history.pushState({}, " ", 'aaa'),出栈history.back() - 替换网站,无历史,
history.replaceState({}, " ", 'aaa') - 发送请求
-
-
route-view
-
// router.js import Vue from 'vue' import Router from 'vue-router' // a. 安装 vue-router 插件 Vue.use(VueRouter) // b.配置路由和组件的映射关系 const router = new VueRouter({}) // main.js // c.在 Vue 实例上挂载路由实例 new Vue({ router, render: h => h(App) }).$mount('#app') // App.vue // d.使用路由 <router-link to="/home">路由跳转,a标签</router-link> this.$router.push('/home') // js路由跳转 <div id="app"> <keep-alive exclude="Detail"> <router-view/> // 组件内容显示 </keep-alive> <MainTabBar></MainTabBar> </div>
-
history 和 hash 的对比
- history,会发送请求;单页应用进行刷新时,需要服务端添加回退路由
- hash,不会发送请求;不足:css中的#,锚点会失效。白屏时间长,需要等待 JavaScript 加载完才渲染 html
-
动态路由
path: '/user/:userId'this.$route.params.userId
路由懒加载
- `const Home = ( ) => import('../components/Home.vue')`
- 路由会定义**很多不同页面**,一般情况下,所有页面打包到**一个 js 文件**中,如果一次性请求的话,会花费不少时间,甚至用户电脑上**出现空白**。这时需要**路由懒加载**来解决
- 将路由对应的组件打包成一个个的 js 代码块,只有这个路由被访问的时候才加载对应组件
- app.js 0.js 1.js ......
-
路由传递参数
-
params
- /user/:id
- this.$route.params.id
this.$router.push('/user/${this.userId}')
-
query
- /user?id=123
- this.$route.query.id
this.$router.push({ path: '/user', query: { id: this.userId } })
-
route 的区别
- $router
- $router 为 VueRouter 实例
- 每个页面的 $router 都一样,全局配置
- 想要导航到不同 URL 用 $router.push
- $route
- $route 为当前 router 跳转的路由对象
- 可以获取 name、path、query、params等
- 路由导航守卫
- 常用钩子函数
- beforeEach
- router.beforeEach( (to, from, next) => { next() })
- to -> 将要跳转的 route 对象
- from -> 将要离开的 route 对象
- next -> 调用该方法后,才能进入下一个钩子
- afterEach
- 导航守卫(全局守卫)
- router.beforeEach(路由进入)
- to, from, next
- router.beforeResolve(路由解析前)
- to, from, next
- router.afterEach(路由离开)
- to, from,唯一一个路由守卫没有 next
- 路由独享守卫
- beforeEnter
- 在路由配置上直接定义
- 组件内的守卫
- beforeRouteEnter
- 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。要传一个回调给 next 来访问组件实例
- beforeRouteUpdate
- this 已经可用了
- beforeRouteLeave
- 这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。
- 完整的导航解析流程
- 在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
- beforeRouteLeave -> beforeEach -> beforeRouteUpdate
- beforeRouteLeave -> beforeEach -> beforeEnter -> beforeRouterEnter -> beforeResolve -> afterEach -> DOM 更新对应组件 -> 调用 beforeRouteEnter 守卫中传给 next 的回调函数
动态添加路由
完整的导航解析流程
-
keep-alive
- 如果被包在里面,所有路径匹配到的视图组件都会被缓存,不然会被销毁,再次进入要创建新组件
- include 、exclude
- activated / deactivated 钩子
5.vuex
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import mutations from './mutations'
import actions from './actions'
Vue.use(Vuex)
const state = {
cartList: []
}
export default new Vuex.Store({
state: state,
getters: getters,
mutations: mutations,
actions: actions
})
// main.js
new Vue({
store,
render: h => h(App)
}).$mount('#app')
- state
- getters
- mutations
- actions
- modules