1. 一个vue
实例只能对应一个容器
❌代码:一个vue
实例对应了两个容器
<div class="app">
</div>
<div class="app">
</div>
<script>
new Vue({
el: '.app'
})
</script>
❌代码:两个vue
实例对应了同一个容器
<div id="app">
<h1>{{name, age}}</h1>
</div>
<script>
new Vue({
el: '#app',
data: {
name: '123'
}
})
new Vue({
el: '#app',
data: {
age: 19
}
})
</script>
2. 容器(#app
)里的代码被称为【vue模板】
3. 插值语法:用于解析标签体内容
4. 指令语法:用于解析标签(包括标签属性、标签体内容、绑定事件…)
5. 单向数据绑定(v-bind
):数据只能从vm.data
流向页面
6. 双向数据绑定(v-model
):数据不仅能从vm.data
流向页面,还能从页面流向vm.data
注意:v-model
只能应用在表单类元素上
v-model:value
可以简写为v-model
,因为v-model
默认收集的就是value
值
7. el
绑定容器的方式
第一种:
new Vue({
el: '#app',
data: {
name: '张三'
}
})
第二种:
vm.$mount(elementOrSelector)
:手动挂载一个未挂载的实例。
let vm = new Vue({
data: {
name: '张三'
}
})
vm.$mount('#root')
8. 路由使用query
参数传值的两种写法
第一种:字符串写法
<router-link :to="`/home/messages?id=${msg.id}&title=${msg.title}`"></router-link>
第二种:对象写法
<router-link :to="{
path: '/home/messages',
query: {
id: msg.id,
title: msg.title
}
}">
</router-link>
组件中接收路由query
参数:
<div>
<h2>消息编号:{{$route.query.id}}</h2>
<h2>消息标题:{{$route.query.title}}</h2>
</div>
9. 路由使用params
参数传值的两种写法
第一种:字符串写法
<router-link :to="`/home/news/${news.id}/${news.title}`">{{news.title}}</router-link>
第二种写法:对象写法
<router-link :to="{
//注意这里只能配置name属性,不能配置path属性
name: 'news',
params: {
id: news.id,
title: news.title
}
}"></router-link>
组件中接收路由params
参数:
<div>
<h2>消息编号:{{$route.params.id}}</h2>
<h2>消息标题:{{$route.params.title}}</h2>
</div>
index.js
中的配置:
const routes = [
{
name: 'Home',
path: '/home',
component: Home,
children: [
{
name: 'news',
path: '/home/news/:id/:title',
component: News
}
]
}
]
10. 路由命名
作用:简化路由的跳转,当路径过长时,to
属性不用配置path
,配置name
来实现路由的跳转
index.js
:
const routes = [
{
path: '/home',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
component: About
}
]
app.vue
:
<template>
<div id="app">
<router-link :to="{name: 'Home'}">Home</router-link>
<router-link :to="{name: 'About'}">About</router-link>
<router-view></router-view>
</div>
</template>
11. 路由的props
写法
第一种:值为对象,该对象中所有的key-value
都会以props
的形式传递给目标组件(News
)。
index.js
配置:
const routes = [
{
name: 'home',
path: '/home',
component: Home,
children: [
{
name: 'news',
path: 'news',
component: News,
props: {
a: 1,
b: 2
}
}
]
}
]
子组件接收props
:
<script>
export default{
name: 'Child',
props: ['a', 'b']
}
</script>
第二种写法:值为布尔值。如布尔值为真,就会把该路由组件收到的所有params
参数,以props
的形式传递给目标组件(News
)。
index.js
配置:
const routes = [
{
name: 'home',
path: '/home',
component: Home,
children: [
{
name: 'news',
path: 'news',
component: News,
props: true
}
]
}
]
父组件传递params
:
<router-link :to="{
//注意这里只能配置name属性,不能配置path属性
name: 'news',
params: {
id: news.id,
title: news.title
}
}"></router-link>
子组件接收props
:
<script>
export default{
name: 'Child',
props: ['id', 'title']
}
</script>
第三种写法:值为函数,接收$route
参数
index.js
配置:
const routes = [
{
name: 'home',
path: '/home',
component: Home,
children: [
{
name: 'news',
path: 'news',
component: News,
props($route){
return {id: $route.query.id, title: $route.query.title}
}
}
]
}
]
子组件接收props
:
<script>
export default{
name: 'Child',
props: ['id', 'title']
}
</script>
12. <router-link>
的replace
属性
用来改变操作浏览器历史记录的模式
<router-link to="/home" replace></router-link>
13. 编程式路由导航
this.$router.push(to)
this.$router.replace(to)
this.$router.back()
this.$router.forward()
this.$router.go()
14. 缓存路由组件
每次切换子组件到另一个子组件时,该子组件都会被销毁。如果我们想要在该子组件保存一些内容,再切换回来就看不到了。可以先把该子组件缓存下来。
include
属性标明要缓存哪个组件,不写include
,所有子组件都会被缓存
作用:让不展示的路由组件保持挂载,不被销毁
<keep-alive :include="['News', 'Messages']">
<router-view></router-view>
</keep-alive>
include
的写法:
第一种:,
分隔,中间不能加空格
<keep-alive include="home,about">
<router-view></router-view>
</keep-alive>
第二种:正则表达式(我还没写过),要用v-bind
绑定
第三种:数组如上
15. actiaved
和deactiaved
生命周期钩子,主要用于路由组件
activated
和deactivated
是配合keep-alive
一起使用的activated
和deactivated
没有keep-alive
的时候是不会被触发的- 在存在
keep-alive
的时候可以将activated
当作created
进行使用deactivated
是组件失活的时候触发
16. 全局前置路由守卫
初始化的时候,每次路由切换之前被调用,配置在/router/index.js
参数:
to
:目标路由from
:源路由(从哪去)next
:调用next()
才会放行
router.beforeEach((to, from, next) => {
const name = localStorage.getItem('user')
if(name === 'root'){
next()
}else{
alert('您无权限查看!')
}
})
17. 后置路由守卫
初始化的时候被调用,每次切换路由之后被调用
参数:
to
:目标路由from
:源路由(从哪去)
//在切换路由后,修改页面的title(放在后置路由守卫里最稳妥,放在前置路由守卫里可能有bug)
router.afterEach((to, from) => {
document.title = to.meta.title || '硅谷系统'
})
18. 独享路由守卫(只有前置,没有守卫)
只对某一个路由做出限制
在routes
的某个路由中配置
{
name: 'home',
path: 'home',
component: Home,
beforeEnter: (to, from, next) => {
console.log(to, from, next)
}
}
19. 组件内路由守卫
在组件中配置
//通过路由规则,进入该组件时被调用
beforeRouteEnter(to, from, next){
console.log('通过路由规则,进入该组件')
/*
可以在这里进行权限校验
*/
//放行
next()
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave(to, from, next){
console.log('通过路由规则,离开该组件')
//放行
next()
}
全局路由守卫(前置和后置),独享路由守卫都配置在router/index.js
文件里,而组件路由守卫配置在相关组件文件里(例如home.vue
)
20. ref
属性
通过 ref 这个 attribute 为子组件赋予一个 ID 引用。
作用一:用来访问子元素(DOM
元素)
代码:
子元素(DOM元素),给按钮添加点击事件访问子元素
<h1 ref="h1">你好</h1>
<button @click="showDom()">点击查看dom</button>
点击事件方法:
methods: {
showDom () {
alert(this.$refs.h1.innerText)
}
}
作用二:用来访问子组件实例对象
代码:
子组件,给按钮添加点击事件访问子组件实例对象
<child-0 ref="child0"></child-0>
<button @click="showChild0">点击查看child0</button>
点击事件方法:
methods: {
showDom () {
console.log(this.$refs.child0)
}
}
21. vuex
- actions:用于响应组件中的动作
- mutations:用于操作数据
- state:用于存储数据
store/index.js
(或vuex/store.js
)的配置
import Vue from 'vue'
import Vuex from 'vuex'
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {}
})
22. mapState
作用:映射state
中的数据为局部计算属性
官网原话:
当一个组件需要获取多个状态的时候,把这些状态都声明为计算属性会有一些重复和冗余。为了解决这个问题,我们可以使用mapState
辅助函数帮助我们生成计算属性。
配置:在组件的computed
属性中配置
第一种写法:对象
export default{
computed: {
...mapState({
getClass: 'class',
getCourse: 'course'
})
}
}
声明了两个计算属性(getClass
和getCourse
)分别用来获取state
中的class
和course
第二种写法(computed
名和状态名一致):数组
export default{
computed: {
...mapState(['class', 'course'])
}
}
mapGetters
作用:将store
中的getter
映射到局部计算属性,语法同上。
23. mapMutations
作用:借助mapMutations
生成对应的方法(method
),方法中会调用commit
去联系mutations
配置:在组件的methods
属性中配置
注意:借助mapMutations
生成method
,调用该方法时需要传递参数
例如:<button @click="minus(n)">-</button>
第一种写法:对象
export default{
methods: {
...mapMutations({
commitPlus: 'plus'
})
}
}
第二种写法(methods
的方法名与mutations
中的属性名相同):数组
export default{
methods: {
...mapMutations(['minus'])
}
}
mapActions
辅助函数将组件的 methods
映射为 store.dispatch
调用。语法同上。
24. 动态组件
动态组件通过<component>
和它的is
属性实现;
语法:
<component :is="currentView"></component>
is
属性的值:
- 已经注册过的组件的名字,或者
- 一个组件的选项对象
实例:Vue动态组件
25. 事件处理
methods
中的方法默认参数为event
,即事件对象
调用和传参的方式:
第一种:
<div id="app">
<button @click="showInfo">点击提示信息</button>
</div>
new Vue({
methods: {
showInfo(event){
console.log(event.target)
}
}
})
第二种:
<div id="app">
<button @click="showInfo(66)">点击提示信息</button>
</div>
new Vue({
methods: {
showInfo(number){
console.log(number)
}
}
})
第三种:
<div id="app">
<button @click="showInfo($event, 66)">点击提示信息</button>
</div>
new Vue({
methods: {
showInfo(event, number){
console.log(event.target, number)
}
}
})
25. mixin
(混入)
混入(mixin)提供了一种非常灵活的方式,来分发vue组件中的可复用功能。
一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
配置:mixin.js
示例:
export const mixin = {
data: function(){
return {
msg: 'hello',
foo: 'abc'
}
},
created: function(){
console.log('hello from mixin!')
}
}
引入混入有两种方式
第一种:局部混入
在单个组件中引入
import {mixin} from './mixin.js'
export default{
mixins: [mixin],
data: function(){
msg: 'goodbye',
bar: 'def'
},
created: function(){
console.log(this.$data)
}
}
第二种方式:全局混入
全局混入会影响每一个创建的Vue实例。
在main.js
文件中配置
import mixin from '../path/mixin.js'
Vue.mixin(mixin)
选项合并
- 数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先
- 同名钩子函数将合并为一个数组,因此都会被调用。混入对象的钩子将在组件自身钩子之前调用。
- 值为对象的选项(如
methods
,components
和directives
),将被合并为同一个对象。键名起冲突,取组件对象的键值对。
26. 插件
插件通常用来为Vue添加全局功能。主要有以下几种:
- 添加全局方法或者
property
- 添加全局资源:指令/过滤器/过渡等
- 通过全局混入添加一些组件选项
- 添加vue实例方法,通过把他们添加到
Vue.prototype
上实现- 一个库,提供自己的API,同时提供上面提到的一个或多个功能
使用插件
通过全局Vue.use()
使用插件,在调用new Vue()
启动应用之前完成
Vue.use(myPlugin)
new Vue({
//...组件选项
})
开发插件
Vue.js 的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
myPlugin.install = function(Vue, opts){...}
27. 过滤器
可以应用于v-bind
表达式和双花括号插值。
过滤器被添加在JS表达式的尾部,由“管道”符号指示。
用法:
局部过滤器
<!-- 在双花括号中 -->
<h1>{{msg | capitalize}}</h1>
<!-- 在v-bind中 -->
<div v-bind:id="msg | capitalize"></div>
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
全局过滤器:(在main.js
中配置)
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
当全局过滤器和局部过滤器重名时,会采用局部过滤器。
28. 自定义指令
注册局部指令
组件中接受一个directives
的选项:
directives: {
focus: {
inserted: function(el){...}
}
}
注册全局指令
Vue.directives('focus', {
inserted: function(el){...}
})
注册指令的语法
注册一个名为fbind
的指令
简单语法:
directives: {
fbind(el, binding){
}
}
完整语法:
directives: {
fbind: {
bind(el, binding){...},
inserted(el, binding){...},
update(el, binding){...}
}
}
三个钩子函数:
bind
:只调用一次,指令第一次绑定到元素时调用inserted
:被绑定元素插入父节点时调用update
:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前(不太懂)componentUpdated
:指令所在组件的VNode及其子VNode全部更新后调用unbind
:只调用一次,指令与元素解绑时调用
钩子函数参数:
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括 v- 前缀。value
:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。oldValue
:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。arg
:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
vnode
:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode
:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
备注:指令名如果是多个单词,在html
中要使用kebab-case命名方式,在js
中还要用""
包上,而不是驼峰法。