官方给出的概念:Vue (读音/vjuː/,类似于 view) 是一套用户构建用户界面的前端框架
数据驱动视图:
双向数据绑定:
MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理。MVVM 指的是 Model、View 和 ViewModel,它们把每个页面都拆分成了这三个部分
{{ message }}
指令(Directives)是 vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构
vue 中的指令按照不同的用途可以分为六大类:
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有三个,分别是:
{{}}
李广
{{}}
vue 提供的 {{}}
语法,专门用来解决 v-text 会覆盖默认文本内容的问题。这种 {{}}
语法的专业名称是插值表达式(Mustache)
姓名:{{ username }}
年龄:{{ age }}
v-text 指令和插值表达式只能渲染纯文本内容。如果要把包含 HTML 标签的字符串渲染为页面的 HTML 元素,则需要用到 v-html 指令
如果需要为元素的属性动态绑定属性值,需要用到 v-bind 属性绑定指令。用法示例如下:
在 vue 中提供的模板渲染语法中,除了支持绑定简单的数据值之外,还支持 JavaScript 表达式的运算
{{ number + 1}}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
vue 提供了 v-on 事件绑定指令,用来辅助程序员为 DOM 元素绑定事件监听,事件处理函数需要在 methods 节点中声明
在原生的 DOM 事件绑定中,可以在事件处理函数的形参处,接收事件参数对象 event。同理,在 v-on 指令所绑定的事件处理函数中,同样可以接收到事件参数对象 event
在使用 v-on 指令绑定事件时,可以使用 () 进行传参
$event
是 vue 提供的特殊变量,用来表示原生的事件参数对象 event。$event
可以解决事件参数对象 event 被覆盖的问题
在事件处理函数中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。因此,vue 提供了事件修饰符的概念,来辅助程序员更方便的对事件的触发进行控制。
事件修饰符 | 说明 |
---|---|
.prevent | 阻止默认行为(阻止 a 链接的跳转、阻止表单的提交) |
.stop | 阻止事件冒泡 |
.capture | 以捕获模式触发当前的事件处理函数 |
.once | 绑定事件只触发一次 |
.self | 只有在 event.target 是当前元素自身时触发事件处理函数 |
在监听键盘事件时,需要判断详细的按键。此时可以为键盘相关的事件添加案件修饰符
vue 提供了 v-model 双向数据绑定指令,用来辅助开发者不操作 DOM 的前提下,快速获取表单的数据
{{ username }}
v-model 指令的修饰符:
修饰符 | 作用 | 示例 |
---|---|---|
.number | 自动将用户的输入值转为数值类型 |
|
.trim | 自动过滤用户输入的首尾空白字符 |
|
.lazy | 在 change 时更新而非 input 时更新 |
|
条件渲染指令用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有两个分别是 v-if 和 v-show
v-if指令
v-show指令
v-if 和 v-show 的区别:
v-else:
v-if 可以单独使用,或配合 v-else 指令一起使用。v-else 指令必须配合 v-if 指令一起使用,否则它将不会被识别
随机数大于 0.5
随机数小于或等于 0.5
v-else-if:
v-else-if 指令,充当 v-if 的 else-if 块,可以连续使用。v-else-if 指令必须配合 v-if 指令一起使用,否则它将不会被识别!
vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。v-for 指令需要使用 item in items 形式的特殊语法,其中:
-
索引是:{{ index }},姓名是:{{ item.name }}
注意:
使用 key 的注意事项:
过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化。过滤器可以用在两个地方:插值表达式和 v-bind 属性绑定
过滤器应该被添加在 JavaScript 表达式的尾部,由管道符进行调用
{{ message | capitalize }}
在创建 vue 实例期间,可以在 filters 节点中定义过滤器
const vm = new Vue({
el: "#app",
filters: {
capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
}
});
在 filters 节点下定义的过滤器,称为私有过滤器,因为它只能在当前 vm 实例所控制的 el 区域内使用。如果希望在多个 vue 实例之间共享过滤器,则可以按照如下的格式定义全局过滤器:
Vue.filter('capitalize', (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
{{ message | filterA | filterB }}
示例代码:
{{ text | capitalize | maxLength }}
Vue.filter('capitalize', (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
Vue.filter('maxLength', (str) => {
if(str.length <= 10) return str;
return str.slice(0, 11) + '...';
});
过滤器的本质是 JavaScript 函数,因此可以接收参数
{{ message | filterA(arg1, arg2) }}
Vue.filter('filterA', (msg, arg1, arg2) => {
});
示例代码:
{{ text | capitalize | maxLength(5) }}
Vue.filter('capitalize', (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
Vue.filter('maxLength', (str, len = 10) => {
if(str.length <= len)return str;
return str.slice(0, len) + '...';
});
生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。
生命周期函数是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行
父组件:
export default {
data() {
return {
message: 'Hello World'
}
}
}
子组件:
父组件传递过来的 msg 值:{{ msg }}
export default {
props: ['msg']
}
子组件:
export default {
data() {
return {
count: 0
}
},
methods: {
add() {
this.count ++;
this.$emit('change-count', this.count);
}
}
}
父组件:
export default {
data() {
return {
parentCount: 0,
}
},
methods: {
changeCount(count) {
this.parentCount = count;
}
}
}
eventBus 模块:
import Vue from 'vue';
export default new Vue();
数据发送方:
import bus from './eventBus.js';
export default {
data() {
return {
msg: 'hello vue.js'
}
},
methods: {
sendMsg() {
bus.$emit('share', this.msg);
}
}
}
数据接收方:
import bus from './eventBus.js';
export default {
data() {
return {
newMsg: ''
}
},
created() {
bus.$on('share', msg => {
this.newMsg = msg;
});
}
}
ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用
每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向的一个空对象
ref 组件
export default {
methods: {
getRef() {
console.log(this.$refs.myRef);
this.$refs.myRef.style.color = 'red';
}
}
}
export default {
methods: {
getRef() {
console.log(this.$refs.childRef);
this.$refs.childRef.getList();
}
}
}
export default {
data() {
return {
inputVisible: false
}
},
methods: {
showInput() {
this.inputVisible = true;
this.$nextTick(() => {
this.$refs.iptRef.focus();
});
}
}
}
动态组件指的是动态切换组件的显示与隐藏
# vue 提供了一个内置的组件,专门用来实现动态组件的渲染
data() {
return {
componentName: 'left'
}
}
默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的
组件保持动态组件的状态
export default {
created() {
console.log('组件被创建了');
},
activated() {
console.log('组件被激活了');
},
deactivated() {
console.log('组件被缓存了');
}
}
# include 属性用来指定只有名称匹配的组件会被缓存,多个组件名之间使用英文的逗号分隔
# 在封装组件时,可以通过 元素定义插槽,从而为用户预留内容占位符
第一个 div 标签
这是最后一个div标签
插槽的内容
插槽提供后备内容(默认内容)。
我是后备(默认)内容
如果在封装组件时需要预留多个插槽节点,则需要为每个
插槽指定具体的 name 名称。这种带有具体名称的插槽叫做具名插槽
在向具名插槽提供内容的时候,可以在一个元素上使用 v-slot 指令,并以 v-slot 参数的形式提供其名称
静夜思
床前明月光,疑是地上霜。
举头望明月,低头思故乡。
作者:李白
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容(v-slot:)替换为字符 #
静夜思
床前明月光,疑是地上霜。
举头望明月,低头思故乡。
作者:李白
在封装组件的过程中,可以为预留的
插槽绑定 props 数据,这种带有 props 数据的
叫做作用域插槽
# 使用 v-slot: 的形式,接收作用域插槽对外提供的数据
{{ scope.user }}
# 作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程
{{ user.name }}
vue 官方提供了 v-text、v-for、v-if 等常用的指令,还允许开发者自定义指令
# 在每个 vue 组件中,可以在 Directives 节点下声明私有自定义指令
directives: {
color: {
bind(el) {
el.style.color = 'red';
}
}
}
# 在使用自定义指令时,需要加上 v- 前缀
App
在 template 结构中使用自定义指令时,可以通过等号(=)的方式,为当前指令动态绑定参数值
data() {
return {
color: 'red',
}
}
App
# 在声明自定义指令时,可以通过形参中的第二个参数,来接收指令的参数值
directives: {
color: {
bind(el, binding) {
el.style.color = binding.value;
}
}
}
bind 函数只调用 1 次,当指令第一次绑定到元素时调用,当 DOM 更新时 bind 函数不会被触发。update 函数会在每次 DOM 更新时被调用
directives: {
color: {
bind(el, binding) {
el.style.color = binding.value;
},
update(el, binding) {
el.style.color = binding.value;
}
}
}
# 如果 bind 和 update 函数中的逻辑完全相同,则对象格式的自定义指令可以简写成函数格式
directives: {
color(el, binding) {
el.style.color = binding.value;
}
}
# 全局共享的自定义指令需要通过 Vue.directives() 进行声明
# 参数一:字符串,表示全局自定义指令的名字
# 参数二:对象,用来接收指令的参数值
Vue.directives('color', function(el, binding) {
el.style.color = binding.value;
});
路由(英文:router)就是对应关系
SPA 指的是一个 web 网站只有唯一的一个 HTML 页面,所有组件的展示与切换都在这唯一的一个页面内完成。此时,不同组件之间的切换需要通过前端路由来实现
Hash 地址与组件之间的对应关系
vue-router 是 vue.js 官方给出的路由解决方案。它只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换
npm i vue-router -S
# 在 src 源代码目录下,新建router/index.js路由模块
# 1. 导入 Vue 和 VueRouter 的包
import Vue from 'vue';
import VueRouter from 'vue-router';
2. 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件
Vue.use(VueRouter);
# 3. 创建路由的实例对象
const router = new VueRouter();
# 4. 向外共享路由的实例对象
export default router;
# 在 src/main.js 入口文件中,导入并挂载路由模块
import Vue from 'vue';
import App from './App.vue';
import router from '@/router';
new Vue({
render: h => h(App),
router: router
}).$mount('#app');
# 在 src/App.vue 组件中,使用 vue-router 提供的 和 声明路由链接和占位符
App 组件
首页
电影
关于
# 在 src/router/index.js 路由模块中,通过 routes 数组声明路由的匹配规则
# 导入需要使用路由切换展示的组件
import Home from '@/components/Home.vue';
import Movie from '@/components/Movie.vue';
import About from '@/components/About.vue';
# 创建路由的实例对象
const router = new VueRouter({
routes: [
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About },
]
})
路由重定向值得是用户在访问地址 A 的时候,强制用户跳转到地址 C,从而展示特定的组件页面。通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由地重定向
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About },
]
})
# 在 About.vue 组件中,声明 tab1 和 tab2 的子路由链接以及子路由占位符
About 组件
tab1
tab2
# 在 src/router/index.js 路由模块中,导入需要的组件,并使用 children 属性声明子路由规则
import Tab1 from '@/components/tabs/Tab1.vue';
import Tab2 from '@/components/tabs/Tab2.vue';
const router = new VueRouter({
routes: [
{
path: '/about',
component: About,
children: [
{ path: 'tab1', component: Tab1 }, // 访问 /about/tab1 时,展示 Tab1 组件
{ path: 'tab2', component: Tab2 }, // 访问 /about/tab2 时,展示 Tab2 组件
]
}
]
})
动态路由指的时:把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在 vue-router 中使用英文的冒号(:)来定义路由的参数项
{ path: '/movie/:id', component: Moive }
# 在动态路由渲染出来的组件中,可以使用 this.$route.params 对象访问动态匹配的参数值
Movie 组件 -- {{ this.$route.params.id }}
为了简化路由参数的获取形式,vue-router 允许在路由规则中开启 props 传参
# 在定义路由规则时,声明 props: true 选项
{ path: '/movie/:id', component: Movie, props: true }
movie组件 --- {{ id }}
在浏览器中,点击链接实现导航的方式,叫做声明式导航。例如:
在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航。例如:
vue-router 提供了许多编程式导航 API,其中最常用的导航 API 分别是:
# 调用 this.$router.push() 方法,可以跳转到指定的 hash 地址,从而展示对应的组件页面
Home 组件
调用 this.$router.replace() 方法,可以跳转到指定的 hash 地址,从而展示对应的组件页面
push 和 replace 的区别:
# 调用 this.$router.go() 方法,可以在浏览器历史中前进和后退
Movie 组件
$router.go 的简化用法:
每次发生路由的导航跳转时,都会触发全局前置守卫。因此在全局前置守卫中,可以对每个路由进行访问权限的控制
# 创建路由的实例对象
const router = new VueRouter();
# 调用路由实例对象的 boforeEach() 方法,即可声明全局前置守卫
router.boforeEach((to, from, next) => {
# to 是将要访问的路由信息对象
# from 是将要离开的路由信息对象
# next 是一个函数,调用 next() 表示放行,允许这次路由导航
});
router.boforeEach((to, from, next) => {
if(to.path === '/main') {
const token = localStorage.getItem('token');
if(token) {
next();
} else {
next('/login');
}
} else {
next(); // 访问的不是主页,直接放行
}
});