MVC
Model - 模型,数据
View - 视图
Controller - 控制器
MVVM
M - Model
V - View
VM - ViewModel
它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,ViewModel 会自动去更新 Model 数据,反之亦然(即当 Model 发生改变时也会自动反映到 ViewModel 上,触发 View 的自动更新渲染)。
Vue
现行两大版本:vue2.x 、 vue3.x
Vue2.x 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性(Object.defineProperty()
)
Vue2.x 底层使用 Object.defineProperty() 来实现数据劫持,Vue3.x 底层使用 Proxy 来实现数据代理。
用于构建用户界面的渐进式框架,核心库只关注视图层。
安装
- 使用
<script>
直接引入:- 使用
<script src="">
方式引入,会添加一个全局变量Vue
- 两种版本:
- 开发版本: 包含完整的警告和调试模式 vue.js
- 生产版本: 压缩混淆,不包含调试模式信息 vue.min.js
- 使用
- npm
- vue-cli
声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。
<div id="app">
{{ message }}
</div>
<script src="./libs/vue.js"></script>
<script>
new Vue({
el: '#app', // View
data: { // Model
message: 'Hello Vue.js'
},
})
</script>
现在数据和 DOM 已经被建立了关联,所有东西都是响应式的
Vue 实例
const vm = new Vue({
el: '',
data: {},
methods: {},
})
注意:
-
在 data 中定义的数据会被挂载到 vm 这个 Vue 对象实例下(即可以直接通过
vm.
来调用 data 中的数据)。注意,在 data 中尽量不要定义以$
或_
开关的字段,因为可能和 Vue 对象自身的属性冲突(以$
或_
开头的数据,不会挂载到 Vue 实例下) -
data
对象中的所有的 property 加入到 Vue 的响应式系统中,但只有当实例被创建时就已经存在于data
中的 property 才是响应式的。 -
$el
-
$data
-
$options
-
在 methods 中定义的方法内部,this 通常指向的是当前创建出的 Vue 实例对象本身(不要使用箭头函数)
模板语法
所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。
插值语法
文本
{{ expression }}
注意,{{ }}
中包含的是 JS 的表达式,会进行 html 文本转义,主要是为了避免 XSS
攻击
<div v-text="expression"></div>
可使用 v-text
来绑定渲染文本表达式的值
原始 HTML
<div v-html="expression"></div>
注意:请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
属性绑定
<div v-text="message" v-bind:title="title"></div>
<div v-text="message" :title="title"></div>
v-bind 可简写为 :
指令
指令,是在标签中添加的自定义属性,以 v-
作为前缀,有特殊的意义(在 Vue 中会对这些属性进行特殊处理)。
指令名称
v-
之后的部分,即为指令名称
参数
指令名称之后以冒号表示
修饰符
以半角句号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定
系统定义的指令
文本:
- v-text:
- v-html:
条件渲染:满足条件的节点即显示,否则隐藏
-
v-show:
-
v-if:
-
v-else-if:
-
v-else:
v-if
vsv-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。相比之下,
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
列表渲染:通常是对数组进行遍历
-
v-for:
<div v-for="n in 10">{{n}} - 需要重复渲染的内容</div> <div v-for="(item, index) in arr">当前:{{ item }},索引:{{ index }}</div> <div v-for="(value, key, index) in stu">{{ key }} - {{ value }} - {{ index }}</div> <div v-for="n of 10">{{n}} - 需要重复渲染的内容</div> <div v-for="(item, index) of arr">当前:{{ item }},索引:{{ index }}</div> <div v-for="(value, key, index) of stu">{{ key }} - {{ value }} - {{ index }}/div>
注意:在进行列表渲染时,尽量为渲染的每一项绑定
key
属性。建议尽可能在使用v-for
时提供key
attributev-if 与 v-for 一起使用:
不推荐同时使用
v-if
和v-for
。当在同一个节点中同时使用 v-if 与 v-for 时:
vue2.x:v-for 的优先级高于 v-if
vue3.x:v-if 的优先级高于 v-for
事件处理:
- v-on:可简写为
@
- 可使用
v-on
去接收一个需要调用的方法名称(事件处理程序函数名称) - 在内联 JavaScript 语句中调用方法,当在事件处理程序调用时需要显式传递参数时,通常使用这种方式
- 可使用
属性绑定:
- v-bind:可简写为
:
表单处理:
- v-model:双向绑定
你可以用 v-model
指令在表单 input
、textarea
及 select
元素上创建双向数据绑定。
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用
value
property 和input
事件;- checkbox 和 radio 使用
checked
property 和change
事件;- select 字段将
value
作为 prop 并将change
作为事件。
插槽:
- v-slot:
其它:
- v-pre:跳过这个元素和它的子元素的编译过程,可以用来显示原始 Mustache 标签
- v-cloak:这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如
[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。 - v-once:一次
Ref
ref
被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs
对象上。
计算属性
可以使用计算属性来代替在表达式中进行的复杂运算,以便于能够更方便的维护与复用逻辑。
计算属性是在选项对象中使用 computed
字段来定义。
特点:计算属性是可被缓存的(计算属性是基于它的响应式依赖进行缓存的,只有当依赖项发生变化时,才会重新计算并缓存)
计算属性 VS 方法
- 计算属性有缓存,方法没有缓存
- 方法中可包含如网络请求类似的副作用操作,计算属性中没有
侦听属性
一种更通用的方式来观察和响应 Vue 实例上的数据变动。
当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
侦听属性是在选项对象中使用 watch
字段来定义。
计算属性 VS 侦听属性
- 缓存
- 计算属性是由一个或多个依赖项计算返回一个值,而侦听器是侦听一个数据的变化引起其它操作或一到多个数据变化
数组变更
变更方法
- push() / pop()
- unshift() / shift()
- splice(index, len, newVal)
- sort() / reverse()
vue 对这七个方法进行了重写,当调用这些方法进行数组修改时,会触发响应式渲染
替换数组
当调用非变更方法时,不会触发响应式渲染,则可以使用替换数组的方式来进行数组更新。
组件化应用构建
组件,即构建应用程序所使用到的部件。
组件系统,允许我们使用小型、独立和通常可复用的组件构建大型应用
在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例。
定义组件选项
const options = {
template: '模板-视图的结构(布局)',
data() {
return {}
},
methods: {},
computed: {},
components: {},
}
注意:
-
template 中定义的结构,必须使用单个根元素包裹
-
data 必须是函数结构,在函数体内部返回一个普通对象
-
为什么 data 要是函数?
组件是可被复用的,当创建同一个组件的不同实例时,如果 data 是普通对象,则不同的实例引用到的是同一个 data 对象,当任意一个实例中对 data 数据进行更新时,其它实例都会受影响,通常这与实际业务不符。
定义成函数,则创建各组件实例时,会调用 data 函数生成组件实例自身私有用到的对象数据,各组件实例间数据是独立的,互不受影响。
-
注册组件
全局注册
Vue.component(name, options)
全局注册的组件可在任意组件中使用到
局部注册
const options = {
components: {
name: componentOptions
}
}
局部注册的组件仅在其父组件内部可使用
渲染组件
利用组件名称作为自定义标签名称使用,来渲染组件。
注意:在使用自定义组件名作为标签名称使用时,要完整书写独立的结束标签,标签名称应该使用短横线命名的规范。
组件通信
组件间进行数据的传递称为组件通信。
父子组件通信
-
父传子:利用属性(props)的方式传递数据。
子组件定义时,在选项中使用 props 定义组件可接收的属性。
父组件中使用到子组件(标签)时,在标签内部书写需要传递给子组件的数据(是 name=value 键值对格式的属性)。
-
子传父:利用事件方式传递数据。
父组件中使用到子组件标签时,利用
v-on
注册一个自定义的事件监听,通常引用在父组件中定义的 methods 方法去处理接收到的数据。在子组件中需要传递数据时,调用
this.$emit(eventName, data)
触发在父组件中绑定的自定义事件并传递数据即可($emit() 的第二个参数是需要传递给父组件的数据)
跨组件层级组件通信
- 转换为父子关系
- event-bus(事件总线):
- 借助 Vue 实例中的
$on()
与$emit()
方法来实现:首先创建一个全局的 Vue 实例对象(bus
) - 在需要接收数据的组件中,利用
bus
来注册事件监听(绑定自定义事件) - 在需要传递数据的组件中,利用
bus
来触发事件并传递数据。
- 借助 Vue 实例中的
- vuex
生命周期
生命周期,指的是组件从开始创建,到最终销毁,所经历的整个过程。
这个过程中会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
图示
生命周期钩子
create 阶段
- beforeCreate():在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用
- created():在实例创建完成后被立即同步调用
mount 阶段
- beforeMount():在挂载开始之前被调用
- mounted():实例被挂载后调用,这时
el
被新创建的vm.$el
替换了。
update 阶段
- beforeUpdate():在数据发生改变后,DOM 被更新之前被调用
- updated():在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用
destroy 阶段
通常会销毁:启动的定时器、未完成的网络请求、打开的网络socket连接等
- beforeDestroy():实例销毁之前调用
- destroyed():实例销毁后调用
插槽
作用:内容分发
在组件定义时,可使用 <slot>
内置组件来占位,定义插槽内容。
在一个组件中,可以使用多个 <slot>
来定义插槽,要区分这些不同的插槽,就需要给 <slot>
添加 name
属性,这就是命名插槽(具名插槽)。
渲染命名插槽是的语法:
-
2.6 之前:
<p slot="slot-name">
即在标签中使用slot
属性指定插槽名称 -
2.6 及之后:可使用
v-slot
指令:<template v-slot:subtitle> <h3>副标题</h3> </template>
v-slot 可简写为
#
,即:<template #subtitle> <h3>副标题</h3> </template>
单文件组件(SFC)
single-file components
文件后缀(扩展)名为 .vue
,解决的问题:
- 全局定义组件可能会出现命名冲突
- 字符串的
template
没有语法高亮 - 对 CSS 的支持不友好
- 没有明显的构建过程
- …
单文件组件语法:
<template>
模板语法
</template>
<script>
// 定义并导出组件的选项对象模块
</script>
<style lang="scss" scoped>
/* 样式 */
div { }
</style>
template
:视图结构script
:交互逻辑style
:样式- lang:使用 css 预处理器,如:scss、less
- scoped:表示所书写的样式仅支持在当前组件中使用,其它组件不受影响
Vue Loader
Vue Loader 是一个 webpack 的 loader,它允许你以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件
Vue CLI
基于 Vue.js 进行快速开发的完整系统。
- 脚手架:快速搭建项目结构
安装
$ npm install -g @vue/cli
# OR
$ yarn global add @vue/cli
安装完毕后,可以在 cmd 命令行中输入:
$ vue --version
如果能够查看到版本信息,则说明安装成功,否则安装失败或环境变量配置有问题。
创建项目
GUI - 图形化用户界面
$ vue ui
命令行
- 执行创建命令:
$ vue create project-name
显示创建项目的向导
- 选择手动选择项目新特性项:
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
> Manually select features
- 选择新特性:
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and
<enter> to proceed)
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
>(*) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
- 选择 vue 版本:
? Choose a version of Vue.js that you want to start the project with
3.x
> 2.x
- 选择 CSS 预处理器:
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
Sass/SCSS (with dart-sass)
> Less
Stylus
- 选择 linter 规范:
? Pick a linter / formatter config:
ESLint with error prevention only
ESLint + Airbnb config
> ESLint + Standard config
ESLint + Prettier
- 选择保存时验证并格式化:
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to pr
oceed)
>(*) Lint on save
( ) Lint and fix on commit
- 选择配置文件存放位置:
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
In package.json
- 是否将上述选择特性保存为预设项:
? Save this as a preset for future projects? (y/N)
如果是 yes,则还需要输入预设项名称
- 安装项目依赖
- 项目创建成功后,进入项目目录,运行任务:
$ cd project-name
$ npm run serve # 或 yarn serve
项目说明
- public 目录中放置的是应用的 html 文件(通常只有一个 index.html)
- src 目录中放置我们自己项目中所书写的源代码
- src 下 main.js 是应用的入口 JS 文件
.eslintrc.js
是 ESLint 的配置文件babel.config.js
是 Babel 的配置文件package.json
是项目配置文件vue.config.js
是 Vue CLI 的配置文件(在 VueCLI4.x 中这个文件需要自己手动创建)
npm scripts
{
"scripts": {
"start": "npm run serve",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
}
- serve: 开发任务,会自动启动开发服务器(webpack-dev-server)
- build:生产任务,构建生产环境下的资源
- lint:验证并格式化代码
安装 VSCode 插件
ESLint
Vetur
Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。---- 工具,用于管理应用中组件间共享的状态(数据)
采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
概念
- store:仓库,用于集中式管理
- state:状态,应用中组件要共享的数据
- mutation:同步更新状态数据的函数,在 vuex 中仅能提交 mutation 来更新状态数据
- action:和 mutation 类似,但可以包含异步操作,不能直接更新状态,而是要提交 mutation 更新
- getter:是 store 中的计算属性
- module:模块,每个模块可以有自己的 state、mutation、action、getter,甚至自己的 module
使用
安装
$ npm i vuex@3.6.2
# 或
$ yarn add vuex@3.6.2
创建 Store
import Vue from 'vue'
import Vuex from 'vuex'
// 使用核心插件 Vuex
Vue.use(Vuex)
// 创建 Store
const store = new Vuex.Store({
state: { // 组件间共享的数据
todos: [],
},
mutations: { // 唯一进行同步更新状态数据的方法
/**
* 添加新待办事项
*/
addTodoItem(state, payload) {
state.todos.push({
id: Math.random(),
title: payload.title,
completed: false,
})
},
},
})
export default store
向根实例中注入 store
import Vue from 'vue'
// 引入 store
import store from './store' // import store from './store/index.js'
new Vue({
store, // 注入 store,这样,在所有后代组件中,都可以使用 this.$store 获取 vuex 的 Store 使用
// render: h => h(App),
}).$mount('#app')
在组件中使用 store
this.$store.state.todos
this.$store.commit(mutationType, payload) // 类似于触发事件
this.$store.getters.allChecked
辅助函数:
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
Vue Router
SPA
single page application(单页面应用程序),即在整个应用中,只有一个 html 页面,在用户与应用之间实现交互时能够动态更新页面内容。
前端路由
利用 hash 或 history 改变不会向后端发起新的 html 请求
模式
- hash:利用 URL 中
#hash
hash 值改变后,不会发送新的网络请求的特点,来实现的路由。使用如#/home
、#/login
类似的方式来表示所请求的前端 URL 资源。 - history:利用 h5 中 history 新增的 API
pushState()
、replaceState()
来实现。其路由的格式与服务端路由 URL 格式一致(比 hash 模式来说,没有多余的如#
之类的符号),所以,这种路由模式要用好,还需要服务端配置。
Vue Router
是 Vue.js 官方的路由管理器,是一个核心插件,与 Vue.js 高度集成。
安装
$ npm i vue-router@3.5.3
# 或
$ yarn add vue-router@3.5.3
定义 VueRouter 对象
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home'
import Login from '@/views/Login'
// 使用路由插件
Vue.use(VueRouter)
// 创建 VueRouter 对象
const router = new VueRouter({
mode: 'hash', // 路由模式,可取 hash、history,默认为 hash
routes: [ // 静态路由的配置信息
{
path: '/home', // 当 URL 中访问地址为 /home 时
component: Home, // 拿 Home 组件渲染
},
{
path: '/login',
component: Login,
},
],
})
// 导出路由对象
export default router
在 Vue 组件中使用 VueRouter 时,可使用 VueRouter 提供的两个内置组件:
- router-link:链接,相当于
<a>
- router-view:视图,用于渲染访问路径所对应的组件
注入 router 到 vue 根实例
// 引入 router
import router from './router'
new Vue({
router,
// render: h => h(App),
}).$mount('#app')
当在 Vue 根实例中注入了 router 后,在 vue 组件中会自动注入如下两个属性:
- $router:代表 VueRouter 对象实例
- $route:代表的是当前激活的路由对象
UI 组件库
通用的已封装好的基础组件,可在各种类型项目中使用。
移动端
-
mint-ui
-
cube-ui
PC端
网络请求
- Fetch API - fetch()
- axios
- vue-resource