vue
MVC 和 MVVM 的区别
-
MVC: 针对后端的分层方式
-
model 数据连接层
-
view 视图层 .html .jsp ...
-
controller 控制层
- router 路由分发
- service 业务逻辑处理
-
ps: mvc 的数据流式单向
-
-
MVVM: 针对前端的分层方式,可以理解为在 MVC,V 层的基础上进一步划分 3 层
- model 数据模型(后端网络请求得到的数据或者是自己写的死数据)
- view 视图层 指定 model 的渲染区域
- view model 管理 model 和 view 对数据的 存、取操作
-
MVP
vue 的模板语法
- 渲染数据
{{msg}}
- 数字计算
{{1+1}}
- 解析函数
{{getData()}}
- 三元运算
{{flag?'显示':'隐藏''}}
指令
渲染数据
-
插值表达式
{{}}
-
v-html
-
v-text
-
v-pre
v-html、v-text、插值表达式有什么区别
- 插值表达式 和 v-text 都是原样输出数据
- v-html 先解析 html 元素再进行渲染
如何解决插值表达式的页面闪烁问题
- 方式 1: 使用 v-text 代替 插值表达式
- 方式 2: 使用 v-cloak 配置显示隐藏的样式
属性绑定
基本使用
-
string
v-bind:属性名称 = "属性值" 简写 :属性名称 = "属性值"
-
object
v-bind:属性名称 = "obj.属性值"
v-bind="obj"
class 样式绑定
-
普通数组
:class="['class1','class2','class3']"
-
数组三元
:class="['class1','class2',flag?'class3':'']"
-
数组对象 :class="['class1','class2',{class3:flag}]"
-
普通对象 :class="{class1:true,class2:true,class3:true}" :class="objStyle"
style 样式绑定
-
object
:style="obj"
-
array
:style="[obj1,obj2]"
v-model 双向数据绑定
-
数据流
- 单向数据绑定: model 改变,view 跟着改变,不能反过来
- 双向数据绑定: model 改变,view 跟着改变,反之亦然
-
小结
v-model 是 vue 中唯一一个可以使用双向数据绑定的指令,可以使用在表单和组件
v-model 的原理
- 使用 v-bind 绑定数据
- 使用 v-on 绑定监听的函数如果数据发生改变重新赋值最新的数据
使用 js 模拟 vue 的双向数据绑定
事件绑定
v-on:事件类型="事件处理函数" 简写 @事件类型="事件处理函数"
修饰符
-
事件修饰符
stop 阻止冒泡 prevent 阻止默认行为 once 只阻止一次,跟随其他修饰符一起使用
-
按键修饰符
enter
列表渲染
基本使用
v-for="(item,index) in 数据"
-
arr
-
arrObj
-
obj
<div v-for="(value,key,index) in obj"></div> -
数字
<div v-for="(count,index) in obj"></div> <!-- count 的数值从 1 开始到指定的数据 -->
v-for 为什么跟随 key 一起使用
key 可以是唯一的 string/number key 建议不要使用 index 配置,因为 index 在使用 unshift 的时候不断的修改
- 给指定的标签添加唯一的标识,防止页面在重新绘制的时候发生错乱
- 确保 model 的值和 view 的值保持一致
... Diff 算法
条件渲染
v-if/v-else-if/v-else/v-show
v-if 和 v-show 的区别
- v-if: 通过 js 操作 DOM 元素的添加和删除
- v-show: 通过 css 控制元素的显示和隐藏
使用场景
- v-if: 逻辑判断或者是少量的 DOM 操作
- v-show: 用于频繁的点击操作
vue 的生命周期
-
创建
beforeCreate
created
最快在这里发起网络请求
-
挂载
beforeMounte
mounted
最快在这里操作 DOM 元素
-
更新
beforeUpdate
updated
-
销毁
beforeDestroy
卸载定时器
destroyed
json-server 模拟接口
基本使用
-
安装 json-server
npm i json-server -g
-
配置数据
data.json
-
运行命令生成接口
json-server --watch --port 8888 --host 10.41.12.152 ./data.json
--watch 实时监听文件的变化
--port 设置端口号 默认为 3000
--host 设置 ip 默认为 locahost
常用接口
get
-
请求所有的资源
-
根据 id 请求资源
-
分页查询
http://localhost:3000/users?_page=1&_limit=2
-
模糊查询
post
- 添加资源
put 更新所有资源,会覆盖 patch 更新指定资源
delete
vue 中发起网络请求
vue-resource
基于 vue 开发的网络请求,2.0 之后不更新了
axios
任意的框架都可以使用,也不需要依赖于任意框架
常用语法
- get
// 字符串写法
axios
.get("/user?ID=12345")
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
// 对象写法
axios
.get("/user", {
params: {
ID: 12345,
},
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
// es7 写法
async function getUser() {
try {
const response = await axios.get("/user?ID=12345");
console.log(response);
} catch (error) {
console.error(error);
}
}
- post
axios
.post("/user", {
firstName: "Fred",
lastName: "Flintstone",
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
- api 写法
// Send a POST request
axios({
method: "post",
url: "/user/12345",
data: {
firstName: "Fred",
lastName: "Flintstone",
},
});
配置根路径
// 方式1
axios.defaults.baseURL = "https://api.example.com";
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;
axios.defaults.headers.post["Content-Type"] =
"application/x-www-form-urlencoded";
// 方式2
const instance = axios.create({
baseURL: "https://api.example.com",
});
过滤器
- 基本使用
Vue.filter('过滤器名称',callback)
-
使用场景
- 插值表达式 {{msg|过滤器名称}}
- 属性绑定 :msg="msg|过滤器名称"
-
ps: 当全局过滤器和局部过滤器同时存在的时候,就近原则使用局部的过滤器
局部过滤器只能使用在当前的实例,全局过滤器可以使用在任意的实例
自定义指令
Vue.directive("指令名称", {
// el 添加该指令的元素的DOM
// binding 是一个对象可以通过 binding.value 获取指令的值
bind(el, binding) {},
inserted() {},
updated() {},
});
// 自动执行了 bind 和 updated
Vue.directive("指令名称", callback);
动画
-
进入
v-enter 起点
v-enter-to 目的点
v-enter-active 进入的时间
-
离开
v-leave 目的点
v-leave-to 终点
v-leave-active 离开的时间
原生动画的基本使用
-
可切换的元素
-
使用 transition 包裹动画元素
-
设置动画的样式
- 设置起点和终端的状态和位置
- 设置进入和离开的时间
第三方动画 animate.css
-
enter-active-class 设置进入的动画
-
leave-active-class 设置离开的动画
-
duration 设置动画的时间,时间不要超过 1000
- number/string 统一配置进入和离开的时间 :duration="800" duration="800"
- object :duration="{enter:500,leave:300}"
列表动画
transition-group
半场动画
beforeEnter
enter
afterEnter
组件
什么是组件化
当我们遇到复杂问题时,很难一次性搞定所有问题,所以这时需要把问题拆解,把小问题都解决后综合起来就能得到这个问题的解决方案,听起来很熟悉吧!其实在动态规划中就是这种思想了,只不过是最优解和解决方案的区分。
组件化也是这种解决问题的思路,当一个项目中的功能逻辑特别复杂时,我们很难一次性完成所有逻辑交互,因为容易发生冗余或回调地狱,一旦某一部分出错,很难追究到哪行代码出现问题。同时一个人的精力是有限的,为了减轻个人的压力,将问题分为小的功能模块,既可以减少管理和维护该界面的成本,也可以适合团队合作。
但其实 Vue 的前端开发不需要很多人,因为它是轻量级的,所以实际项目中只需要美工人员把设计好的原型发给一两个前端开发人员就行了,至于为什么需要这么少的开发人员,很大程度上因为 Vue 的组件化开发让业务逻辑更清晰。
ps: 组件化: 是针对前端 ui 的一种划分方式 ,把前端的业务分层多个组件单独管理 模块化: 一个 js 文件就是一个模块,在一个 js 文件中引入另一个 js 文件
vue 组件化思想
- 组件化的思想让我们能够开发出一个个独立且可复用的小组件来构造我们的应用。
- 每一个应用(功能)都可以抽象成一个组件树。
- 尽可能的将页面拆分成小且可复用的组件。这样让我们的代码更加方便组织和管理,并且扩展性也更强。
vue 组件化的好处
- 组件是独立和可复用的代码组织单元。组件系统是 vue 核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用;
- 组件化开发能大幅度提高应用开发效率、测试性、复用性等;
- 能让 web 前端代码实现“高内聚 低耦合”,使得前端开发的过程变成搭积木的过程。
组件的基本使用
- 定义组件
const Login = {
template: ``,
};
const Login = Vue.extend({
template: ``,
});
- 注册组件
// 全局注册
Vue.component("组件名称", 组件的返回值);
// 局部注册
new Vue({
components: {
组件名称: 组件的返回值,
},
});
-
渲染组件
- 以组件名称作为标签直接渲染
- 以 component 渲染,通过 is 属性设置具体渲染那个组件,一般用于组件的切换
组件中的 data 为什么是一个 function
动态组件和异步组件
组件通信(9 种方式)
每个组件的数据都是独立的,组件之间通信需要按照一定的方式传递数据
父传子
- 在渲染的子组件上使用 v-bind 的方式传递父组件的数据
- 在子组件中使用 props 接受传递的数据
-
ps:
- props 的对象写法可以约束传递的数据的类型
- props 的对象写法可以设置属性的默认值
- props 是只读的不能被修改
子传父
- 在渲染的子组件上使用 v-on 的方式监听父组件的函数
- 在子组件中使用$emit 的方式调用函数,调用的同时传递子组件的数据
兄弟组件传值(事件总线)
b --> a
- 创建一个空的 vue 实例 (eventBus)
- 在组件 a 中使用 $on 的方式监听函数
- 在组件 b 中使用 $emit 调用函数,调用的同时传递数据
爷孙传值 listeners
跨多组件传值 provide、inject
parent、$root
组件插槽
可以在父组件中直接修改子组件的 ui
匿名插槽
具名插槽
作用域插槽
插槽的优点
- 可以在父组件中定制子组件的 ui
- 可以解决多层组件传参问题
- 可以对组件进行抽离方便管理
路由
路由是一种对应关系
什么是后端路由
客户端请求的 url 地址和服务端对该地址的处理函数的对应关系
什么是前端路由
路由是根据不同的 url 地址展示不同的内容或页面
前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的
hash
history
什么时候使用前端路由
在单页面应用,大部分页面结构不变,只改变部分内容的时候使用
前端路由有什么优缺点
-
优点:
用户体验好,不需要每次都从服务器全部获取,快速展现给用户
-
缺点:
- 不利于 SEO
- 使用浏览器的前进,后退键的时候会重新发送请求,没有合理利用缓存
- 单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置
vue 中路由基本使用
-
通过 script 标签引入 vue-router
-
定义组件
-
实例化路由对象 new VueRouter
-
配置路由的规则
#/home ---> 组件
-
挂载路由
设置路由和 vue 的关系
-
渲染路由
router-view
router-link
路由高亮
- router-link-active
- linkActiveClass: 'active'
路由重定向、404
- redirect
{
path: '/',
redirect: '/home'
}'
- 404
{
path: '*',
component: NotFoundPage
}'
路由传参
-
query
#/home?name=fly&age=18
-
params
#/home/fly/18
{ path: '/home/:name/:age', component: Home }'
路由编程式导航
this.$router.push()
嵌套路由
{
path: '/home',
component: Home,
children: [
{
path: '/home/recomment',
component: Recomment
}
]
}
命名视图路由
{ path: '/', components: { default: Header, main: Main, footer: Footer } }
<router-view></router-view>
<router-view name="main"></router-view>
<router-view name="footer"></router-view>
路由进阶
-
beforeEach
全局路由前置守卫
router.beforeEach((to, from, next) => {}); -
afterEach()
全局路由后置守卫
-
路由独享守卫
beforeEnter()
-
组件内置守卫
beforeRouteEnter(to,from,next) {
}
methods、watch、computed 有什么区别
-
methods:适合用于业务逻辑处理
多次调用的时候不会缓存
-
watch:比较适合侦听单个数据,或者是路由
可以侦听实例上的任意属性
-
computed:适合计算多个属性的结果
可以缓存数据方便下次使用
watch 的两种用法
- 浅层侦听
- 深度侦听