我想要的,时间自然会给我。
年龄也不会是我的阻碍,反而会是我的骄傲。:
我不用在某个年龄段必须做某事,
不要让任何人打乱自己的节奏。
---------------------摘
加油生活:我要努力呀
第一章,Vue基础,
1). 一位华裔前Google工程师(尤雨溪)开发的前端js库
2). 作用: 动态构建用户界面,渐进式的javaScript框架
3). 特点:
- * 遵循MVVM模式
- * 编码简洁, 体积小, 运行效率高, 移动/PC端开发
- * 它本身只关注UI, 可以轻松引入vue插件和其它第三库开发项目
4). 与其它框架的关联:
- * 借鉴angular的模板和数据绑定技术
- * 借鉴react的组件化和虚拟DOM技术
5). vue包含一系列的扩展插件(库):
- * vue-cli: vue脚手架
- * vue-resource(axios): ajax请求
- * vue-router: 路由
- * vuex: 状态管理
- * vue-lazyload: 图片懒加载
- * vue-scroller: 页面滑动相关
- * mint-ui: 基于vue的组件库(移动端)
- * element-ui: 基于vue的组件库(PC端)
Vue的基本使用,对象的选项
基本使用
- 引入vue.js
- 创建Vue实例对象(vm), 指定选项(配置)对象
- el : 指定dom标签容器的选择器
- data : 指定初始化状态数据的对象/函数(返回一个对象)
- 3). 在页面模板中使用{{}}或vue指令
Vue对象的选项
. el
- 指定dom标签容器的选择器
- Vue就会管理对应的标签及其子标签
. data
- 对象或函数类型
- 指定初始化状态属性数据的对象
- vm也会自动拥有data中所有属性
- 页面中可以直接访问使用
- 数据代理: 由vm对象来代理对data中所有属性的操作(读/写)
. methods,用以事件监听
- 包含多个方法的对象
- 供页面中的事件指令来绑定回调
- 回调函数默认有event参数, 但也可以指定自己的参数
- 所有的方法由vue对象来调用, 访问data中的属性直接使用this.xxx
. computed:属性计算
- 包含多个方法的对象
- 对状态属性进行计算返回一个新的数据, 供页面获取显示
- 一般情况下是相当于是一个只读的属性
- 利用set/get方法来实现属性数据的计算读取, 同时监视属性数据的变化
- 如何给对象定义get/set属性
- 在创建对象时指定: get name () {return xxx} / set name (value) {}
- 对象创建之后指定: Object.defineProperty(obj, age, {get(){}, set(value){}})
. watch
- 包含多个属性监视的对象
- 分为一般监视和深度监视
- 一般监听:直接写一个监听处理函数,当每次监听到 cityName 值发生改变时,执行函数。也可以在所监听的数据后面直接加字符串形式的方法名:
- 深度监视:用watch时有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。 比如当父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时,也需要执行函数,此时就需要将immediate设为true。听的数据后面写成对象形式,包含handler方法和immediate,之前我们写的函数其实就是在写这个handler方法;mmediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。
- 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。对象数组中对象的属性变化则需要deep深度监听。
- 另一种添加监视方式: vm.$watch('xxx', function(value){})
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Vue.js -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
1,计算属性:在computed属性对象中定义属性的方法,在页面中使用{{方法名}}或v-model 显示计算结果
2,通过vm对象的$watch()或watch配置来监视指定的属性,当属性变化时,回调函数自动调用,在函数内部
进行计算。
3,通过getter和setter实现属性数据的显示和监听,计算属性存在缓存,多次读取只执行一次getter计算。
-->
<!--view视图-->
<div id="app">
<input type="text" v-model="username" />
<h2>双大括号表示</h2>
<p> {{ username }}</p>
<p>
{{ username.toUpperCase() }}
</p>
<!-- textContent-->
<p v-text = "username"></p>
<!-- innerHTML-->
<P v-html = "username"></P>
<!-- 指令一,强制数据绑定-->
<img v-bind:src="imgUrl">
<img :src = "imgUrl">
<!-- 指令二,绑定事件监听-->
<button v-on:click = "test">test1</button>
<!-- //省略前缀-->
<button @click = "test">test1</button>
<button @click = "test1('liruilong')">test1</button>
<span style="align-content: baseline"></span>
姓:<input type="text" placeholder="First Name" v-model="firstName"><br>
名:<input type="text" placeholder="Last Name" v-model="lastName"><br>
姓名单:<input type="text" placeholder="Full Name" v-model="fullname1"><br>
姓名单:<input type="text" placeholder="Full Name" v-model="fullname2"><br>
姓名双:<input type="text" placeholder="Full Name" v-model="fullname3"><br>
</div>
<script type="text/javascript">
// 创建Vue实例
const vm = new Vue({
el: '#app', // 选择器
data: { // 数据
username: '<a href = "Hello Vue!" > hello vue</a>',
imgUrl:'C:\\Users\\12249\\Desktop\\假期任务.png',
firstName:'li',
lastName:'ruilong',
fullname2:'li ruilong'
},
//事件监听
methods:{
test() {
alert("liruilong")
},
test1(content) {
alert(content)
},
},
// 计算属性
computed:{
// 初始化,相关属性变化是发生变化,单项关联
fullname1() {
return this.firstName + ' '+this.lastName
},
//双向关联
fullname3:{
// 回调函数,计算并返回当前属性的值,你定义的,你没有调用,最后执行了
// 读取值的时候执行
get(){
return this.firstName + ' '+this.lastName
},
//回调函数,当属性值发生改变时回调,更新相关的属性值
set(value){
const name = value.split(' ');
this.firstName = name[0]
this.lastName = name[1]
}
}
},
// 属性监视的对象
watch:{
firstName: function (value) {
this.fullname2 = value + ' ' + this.lastName
},
// lastName: function (value) {
// this.fullname2 = value + ' ' + this.firstName
// }
}
});
vm.$watch('lastName', function (value) {
this.fullname = this.firstName + ' ' + value
})
</script>
<!--MVVM-->
</body>
</html>
样式绑定
某些元素的样式是变化的,class和style绑定就是专门用来实现动态样式效果的技术
- class绑定:class = '对象/字符串/数组';
- style绑定:style = '{属性值}' 对应data中的属
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
<style>
.aClass{
color: red;
}
.bClass{
color: blue;
}
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="name">
<!--某些元素的样式是变化的,class和style绑定就是专门用来实现动态样式效果的技术
class绑定:class = '对象/字符串/数组';
style绑定:style = '{属性值}' 对应data中的属性
-->
<p :class="a"> {{name}}</p>
<p :class="{aClass: isA, bClass: isB }"> {{name}}</p>
<p :style="{color: activeColor, fontSize:fontSize +'px' }"> {{name}}</p>
<button @click="update" > 更新 </button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data:{
a:'aClass',
name:'liruilong',
isA: true,
isB: false,
activeColor: 'red',
fontSize:20
},
methods:{
update(){
this.a = 'bClass'
this.isA = false
this.isB = true
this.activeColor = "blue"
this.fontSize = 30
}
}
})
</script>
</body>
</html>
vue内置指令
v-text/v-html: 指定标签体
- * v-text : 当作纯文本
- * v-html : 将value作为html标签来解析
v-if v-else v-show: 显示/隐藏元素
- * v-if : 如果vlaue为true, 当前标签会输出在页面中
- * v-else : 与v-if一起使用, 如果value为false, 将当前标签输出到页面中
- * v-show: 就会在标签中添加display样式, 如果vlaue为true, display=block, 否则是none
v-for : 遍历
- * 遍历数组 : v-for="(person, index) in persons"
- * 遍历对象 : v-for="value in person" $key
- 列表的搜索和排序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列表渲染</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="demo">
<h1>测试:v-for遍历数组</h1>
查询: <input v-model="searchName" type="text"/><br>
<ul>
<li v-for="(p, index) in filterPer" :key="index">
{{ p.name }}-{{ p.age }}-{{index}}
<button @click="del(index)">删除</button>
<button @click="upd(index,{name:'Tom', age:18})">更新</button>
</li>
<li v-for="(value, key) in person[0] " :key="key"> {{ value }}-{{ key }}</li>
</ul>
<button @click="setOrderby(0)">年龄升序</button>
<button @click="setOrderby(1)">年龄降序</button>
<button @click="setOrderby(2)">年龄原序</button>
</div>
<script type="text/javascript">
new Vue({
el:'#demo',
data: {
orderbys:1,
searchName:'',
person : [
{name:'Tom', age:138},
{name:'jack', age:41},
{name:'jack', age:431}],
},
methods:{
del(index){
this.person.splice(index, 1)
//vue重写了数组中的一系列改变数组内部的数据的方法(先调用原生更新界面),数组内部改变界面自动变换,有绑定
},
upd(index, newP){
alert("")
//vue本身只是监视了数组的改变,没有监视数组内部数据的改变
// this.person[index] = newP这种不行.
this.person.splice(index, 1, newP)
},
setOrderby(orderbys){
this.orderbys = orderbys
}
},
computed:{
filterPer(){
// ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
const {searchName , person } = this
// 过滤后显示的数组
let fPer;
fPer = person.filter(p => p.name.indexOf(searchName) !== -1 )
if(orderbys !== 0){
fPer.sort(function (p1, p2) {
if (orderbys == 1){
return p2.age - p1.age
}else {
return p1.age - p2.age
}
})
}
return fPer
},
}
})
</script>
</body>
</html>
v-on : 绑定事件监听
- * v-on:事件名, 可以缩写为: @事件名
- * 监视具体的按键: @keyup.keyCode @keyup.enter
- * 停止事件的冒泡和阻止事件默认行为: @click.stop @click.prevent
- * 隐含对象: $event
v-bind : 强制绑定解析表达式
- * html标签属性是不支持表达式的, 就可以使用v-bind
- * 可以缩写为: :id='name'
- * :class
- * :class="a"
- * :class="{classA : isA, classB : isB}"
- * :class="[classA, classB]"
- * :style
- :style="{color : color}"
v-model:数据绑定
- * 双向数据绑定
- * 自动收集用户输入数据(表单数据的绑定)
ref : 标识某个标签
- * ref='xxx'
- * 读取得到标签对象: this.$refs.xxx
常用内置指令
v:text : 更新元素的 textContent
v-html : 更新元素的 innerHTML
v-if : 如果为true, 当前标签才会输出到页面
v-else: 如果为false, 当前标签才会输出到页面
v-show : 通过控制display样式来控制显示/隐藏
v-for : 遍历数组/对象
v-on : 绑定事件监听, 一般简写为@
v-bind : 强制绑定解析表达式, 可以省略v-bind
v-model : 双向数据绑定
ref : 为某个元素注册一个唯一标识, vue对象通过$refs属性访问这个元素对象
v-cloak : 使用它防止闪现表达式, 与css配合: [v-cloak] { display: none }
Vue生命周期:
1. vue对象的生命周期
- 1). 初始化显示
- * beforeCreate()
- * created()
- * beforeMount()
- * mounted()
- 2). 更新状态
- * beforeUpdate()
- * updated()
- 3). 销毁vue实例: vm.$destory()
- * beforeDestory()
- * destoryed()
2. 常用的生命周期方法
- created()/mounted(): 发送ajax请求, 启动定时器等异步任务
- beforeDestory(): 做收尾工作, 如: 清除定时器
动画处理:
1. vue动画的理解
- 操作css的trasition或animation
- vue会给目标元素添加/移除特定的class利用vue去操控css的transition/animation动画模板: 使用<transition name='xxx'>包含带动画的标签
2. 基本过渡动画的编码
- 1). 在目标元素外包裹<transition name="xxx">
- 2). 定义class样式
- 3). 过渡的类名
- xxx-enter-active: 指定显示的transition
- xxx-leave-active: 指定隐藏的transition
- xxx-enter: 指定隐藏时的样式
- 1>. 指定过渡样式: transition
- 2>. 指定隐藏时的样式: opacity/其它
Vue过滤器:
功能: 对要显示的数据进行特定格式化后再显示, 并没有改变原本的数据, 可是产生新的对应的数据。
自定义指令:
1). 注册全局指令
Vue.directive('my-directive', function(el, binding){
el.innerHTML = binding.value.toUpperCase() })
2). 注册局部指令
directives : { 'my-directive' : function(el, binding) {
el.innerHTML = binding.value.to·UpperCase() } }
3). 使用指令
<div v-my-directive='xxx'>
第二章,VueDemo
1. vue脚手架
- 用来创建vue项目的工具包
- 创建项目:
- npm install -g vue-cli
- vue init webpack VueDemo
- 开发环境运行:
- cd VueDemo
- npm install
- npm run dev
- 生产环境打包发布
- npm run build
- npm install -g serve
- serve dist
- http://localhost:5000
2. eslint
用来做项目编码规范检查的工具
基本原理: 定义了很多规则, 检查项目的代码一旦发现违背了某个规则就输出相应的提示信息
有相应的配置, 可定制检查
3. 组件化编程
vue文件包含3个部分
<template>
<div></div>
</template>
<script>
export default {
props: []/{}
data(){},
computed: {}
methods: {},
watch: {}
filters: {}
directives: {}
components: {}
}
</script>
<style>
</style>
组件化编码的基本流程
- 1). 拆分界面, 抽取组件
- 2). 编写静态组件
- 3). 编写动态组件
- 初始化数据, 动态显示初始化界
- 实现与用户交互功能
组件通信的5种方式
- props:父子组件间通信的基本方式,
- 属性值的2大类型:一般: 父组件-->子组件 函数: 子组件-->父组件
- 隔层组件间传递: 必须逐层传递(麻烦),兄弟组件间: 必须借助父组件(麻烦)
- vue的自定义事件:子组件与父组件的通信方式,用来取代function props,不适合隔层组件和兄弟组件间的通信
- pubsub第三方库:(消息订阅与发布)适合于任何关系的组件间通信
- slot:通信是带数据的标签,注意: 标签是在父组件中解析
- vuex(后面单独讲):多组件共享状态(数据的管理),组件间的关系也没有限制,功能比pubsub强大, 更适用于vue项目
实例:
实例:
4. ajax
相关库:
- vue-resource: vue插件, 多用于vue1.x
vue-resource使用
// 引入模块
import VueResource from 'vue-resource'
// 使用插件
Vue.use(VueResource)
// 通过vue/组件对象发送ajax请求
this.$http.get('/someUrl').then((response) => {
// success callback
console.log(response.data) //返回结果数据
}, (response) => {
// error callback
console.log(response.statusText) //错误信息
})- axios: 第三方库, 多用于vue2.
axios使用
// 引入模块
import axios from 'axios'
// 发送ajax请求
axios.get(url)
.then(response => {
console.log(response.data) // 得到返回结果数据
})
.catch(error => {
console.log(error.message)
})
Vue组件库:
- * mint-ui: 基于vue的组件库(移动端)
- * element-ui: 基于vue的组件库(PC端)
5. vue-router
vue用来实现SPA的插件(单页应用程序)
速度:更好的用户体验,让用户在web app感受native app的速度和流畅,
·MVVM:经典MVVM开发模式,前后端各负其责。
·ajax:重前端,业务逻辑全部在本地操作,数据都需要通过AJAX同步、提交。
·路由:在URL中采用#号来作为当前视图的地址,改变#号后的参数,页面并不会重载。
- 使用vue-router
1. 创建路由器: router/index.js
new VueRouter({
routes: [
{ // 一般路由
path: '/about',
component: about
},
{ // 自动跳转路由
path: '/',
redirect: '/about'
}
]
})
2. 注册路由器: main.js
import router from './router'
new Vue({
router
})
3. 使用路由组件标签:
<router-link to="/xxx">Go to XXX</router-link>
<router-view></router-view>- 编写路由的3步
- 1. 定义路由组件
- 2. 映射路由
- 3. 编写路由2个标签
嵌套路由
children: [
{
path: '/home/news',
component: news
},
{
path: 'message',
component: message
}
]
向路由组件传递数据
params: <router-link to="/home/news/abc/123">
props: <router-view msg='abc'>
缓存路由组件
<keep-alive>
<router-view></router-view>
</keep-alive>
路由的编程式导航
this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
this.$router.back(): 请求(返回)上一个记录路由
实例:
1. vuex- github站点: https://github.com/vuejs/vuex
- 在线文档: https://vuex.vuejs.org/zh-cn/
- 简单来说: 对应用中组件的状态进行集中式的管理(读/写),
- 分为两部分,注册和使用,注册一般在单独的js文件里定义一个stort对象,然后注册state,actios,mutations.
- state里存放需要管理的对象,mutations用于更新对象的值,而action用于做一些异步操作,同时提交mutations的更新操作.
- mutations里的方法可以随时提交.一般在其他的组件的methods对象里事件方法处理.
- state里的数据一般放在computed里,直接使用,等同于在data里声明.
- action用于异步更新值,对同时对于mutations里的方法提交.
2. 状态自管理应用
- state: 驱动应用的数据源
- view: 以声明方式将state映射到视图
- actions: 响应在view上的用户输入导致的状态变化(包含n个更新状态的方法)
![单向数据流]
3. 多组件共享状态的问题
- 多个视图依赖于同一状态
- 来自不同视图的行为需要变更同一状态
- 以前的解决办法
- * 将数据以及操作数据的行为都定义在父组件
- * 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
vuex就是用来解决这个问题的 - 把组件的共享状态抽取出来,以一个全局单例模式管理,在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
- ![vuex结构]
4. vuex的核心概念
1). state
,通过在根实例中注册 store
选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store
访问到。所以对于state而言,分为两部分,定义和使用,一般在定义vuex对象的里定义全局的state对象.
const state = {
xxx: initValue
}
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性,
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState
传一个字符串数组。
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
2). mutations
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
包含多个直接更新state的方法(回调函数)的对象,
谁来触发: action中的commit('mutation名称')只能包含同步的代码, 不能写异步代码
const mutations = {
yyy (state, data) {
// 更新state的某个属性
}
}
当需要在对象上添加新属性时,你应该
使用
Vue.set(obj, 'newProp', 123)
, 或者以新对象替换老对象。例如,利用对象展开运算符我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
你可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
辅助函数将组件中的 methods 映射为 store.commit
调用(需要在根节点注入 store
)。
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
3). actions
包含多个事件回调函数的对象,通过执行: commit()来触发mutation的调用, 间接更新state,谁来触发: 组件中: $store.dispatch('action名称') // 'zzz',,可以包含异步代码(定时器, ajax)
const actions = {
zzz ({commit, state}, data1) {
commit('yyy', data2)
}
}
- 4). getters:包含多个计算属性(get)的对象,谁来读取: 组件中: $store.getters.xxx
const getters = {
mmm (state) {
return ...
}
}
- 5). modules:包含多个module,一个module是一个store的配置对象,与一个组件(包含有共享数据)对应
- 6). 向外暴露store对象
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
- 7). 组件中:
import {mapGetters, mapActions} from 'vuex'
export default {
computed: mapGetters(['mmm'])
methods: mapActions(['zzz'])
}
{{mmm}} @click="zzz(data)"
- 8). 映射store
import store from './store'
new Vue({
store
})
9). store对象
- 1.所有用vuex管理的组件中都多了一个属性$store, 它就是一个store对象
- 2.属性:state: 注册的state对象,getters: 注册的getters对象
- 3.方法:dispatch(actionName, data): 分发action
5. 将vuex引到项目中
1). 下载: npm install vuex --save
2). 使用vuex
1.store.js
import Vuex from 'vuex'
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules
})
2.main.js
import store from './store.js'
new Vue({
store
})
实例:
优化:
实例:
action.js
/*
包含n个用于间接更新状态的方法的对象模块
包含多个接受组件通知触发mutation调用间接状态的方法的对象.
*/
import {ADD_TODO, DELETE_TODO, SELECT_ALL_TODOS, DELETE_COMPLETE_TODOS} from './mutation-types'
export default {
addTodo ({commit}, todo) {
// 提交一个comutation请求
commit(ADD_TODO, {todo}) // 传递给mutation的是一个包含数据的对象
},
deleteTodo ({commit}, index) {
commit(DELETE_TODO, {index})
},
selectAll ({commit}, isCheck) {
commit(SELECT_ALL_TODOS, {isCheck})
},
deleteCompleteTodos ({commit}) {
commit(DELETE_COMPLETE_TODOS)
}
}
getters.js
/*
包含n个基于state的getter计算属性方法的对象模块
*/
export default {
// 总数量
totalSize (state) {
return state.todos.length
},
// 完成的数量
completeSize (state) {
return state.todos.reduce((preTotal, todo) => preTotal + (todo.complete?1:0) ,0)
},
// 判断是否需要全选
isAllSelect (state, getters) {
return getters.completeSize===getters.totalSize && getters.completeSize>0
}
}
mutation-types.js
/*
包含n个mutation名称常量
*/
export const ADD_TODO = 'add_todo' // 添加todo
export const DELETE_TODO = 'delete_todo' // 删除todo
export const SELECT_ALL_TODOS = 'select_all_todos' // 全选/全不选todos
export const DELETE_COMPLETE_TODOS = 'delete_complete_todos' // 删除所有选中的
mutations.js
/*
包含n个用于直接更新状态的方法的对象模块,由action触发的直接更新状态.
*/
import {ADD_TODO, DELETE_TODO, SELECT_ALL_TODOS, DELETE_COMPLETE_TODOS} from './mutation-types'
export default {
[ADD_TODO] (state, {todo}) { // 方法名不是ADD_TODO, 而是add_todo
state.todos.unshift(todo)
},
[DELETE_TODO] (state, {index}) {
state.todos.splice(index, 1)
},
[SELECT_ALL_TODOS] (state, {isCheck}) {
state.todos.forEach(todo => todo.complete = isCheck)
},
[DELETE_COMPLETE_TODOS] (state) {
state.todos = state.todos.filter(todo => !todo.complete)
}
}
state.js
/*
状态对象模块
*/
import storageUtils from '../utils/storageUtils'
export default {
todos: storageUtils.readTodos()
}
Vue面试整理:
1. Vue.js介绍
- Vue.js是一个轻巧、高性能、可组件化的MVVM库,同时拥有非常容易上手的API;
- Vue.js是一个构建数据驱动的Web界面的库。
- Vue.js是一套构建用户界面的 渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合。另一方面,Vue 完全有能力驱动采用单文件组件和 Vue生态系统支持的库开发的复杂单页应用。数据驱动+组件化的前端开发。
- 简而言之:Vue.js是一个构建数据驱动的 web 界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API实现响应的数据绑定和组合的视图组件。核心是一个响应的数据绑定系统。
2、使用Vue的好处
- vue两大特点:响应式编程、组件化
- vue的优势:轻量级框架、简单易学、双向数据绑定、组件化、视图、数据和结构的分离、虚拟DOM、运行速度快
3、MVVM定义
MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。
- 【模型】指的是后端传递的数据。
- 【视图】指的是所看到的页面。
- 【视图模型】mvvm模式的核心,它是连接view和model的桥梁。
- 它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
- 二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。
- 这两个方向都实现的,我们称之为数据的双向绑定。
总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信
4、Vue的生命周期
- beforeCreate(创建前) 在数据观测和初始化事件还未开始
- created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
- beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
- mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。只执行一次.
- beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
- updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
- beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
- destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
2)、vue生命周期的作用是什么
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
(3)、vue生命周期总共有几个阶段
答:可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
5、Vue的响应式原理
当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
6、第一次页面加载会触发哪几个钩子?
触发 下面这几个beforeCreate, created, beforeMount, mounted ,并在mounted的时候DOM渲染完成
7、vue中data必须是一个函数
对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。
8、vue中做数据渲染的时候如何保证将数据原样输出?
- v-text:将数据输出到元素内部,如果输出的数据有HTML代码,会作为普通文本输出
- v-html:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染
- {{}}:插值表达式,可以直接获取Vue实例中定义的数据或函数,使用插值表达式的时候,值可能闪烁;而使用v-html、v-text不会闪烁,有值就显示,没值就隐藏
9、active-class是哪个组件的属性?
vue-router模块的router-link组件。
10、vue-router有哪几种导航钩子?
三种。
- 一种是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
- 第二种:组件内的钩子;
- 第三种:单独路由独享组件
11、$route和$router的区别
$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等
12、vue几种常用的指令
v-for 、 v-if 、v-bind、v-on、v-show、v-else
13、v-if 和 v-show 区别
v-if按照条件是否渲染,v-show是display的block或none
14、vue常用的修饰符?
- .prevent: 提交事件不再重载页面;
- .stop: 阻止单击事件冒泡;.self: 当事件发生在该元素本身而不是子元素的时候会触发;
- .capture: 事件侦听,事件发生的时候会调用
15、vue-loader是什么?使用它的用途有哪些?
- 解析.vue文件的一个加载器,跟template/js/style转换成js模块。
- 用途:js可以写es6、style样式可以scss或less、template可以加jade等
16、computed、watch、methods的区别
- computed计算属性是用来声明式的描述一个值依赖了其它的值。当你在模板里把数据绑定到一个计算属性上时,Vue 会在其依赖的任何值导致该计算属性改变时更新 DOM。这个功能非常强大,它可以让你的代码更加声明式、数据驱动并且易于维护。
- watch监听的是你定义的变量,当你定义的变量的值发生变化时,调用对应的方法。就好在div写一个表达式name,data里写入num和lastname,firstname,在watch里当num的值发生变化时,就会调用num的方法,方法里面的形参对应的是num的新值和旧值,而计算属性computed,计算的是Name依赖的值,它不能计算在data中已经定义过的变量。
- methods方法,函数,绑定事件调用;不会使用缓存
17、什么是js的冒泡?Vue中如何阻止冒泡事件?
- js冒泡概念:当父元素内多级子元素绑定了同一个事件,js会依次从内往外或者从外往内(?)执行每个元素的该事件,从而引发冒泡
- js解决冒泡:event.stopPropagation()
- vue解决冒泡: 事件.stop,例如:@click.stop="" ,@mouseover.stop=""
18、vue 组件通信
1.父组件与子组件传值
父组件传给子组件:子组件通过props方法接受数据;
子组件传给父组件:$emit方法传递参数
2.非父子组件间的数据传递,兄弟组件传值
eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。也可使用vuex
19、<keep-alive></keep-alive>的作用是什么?
<keep-alive></keep-alive>包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。 大白话: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
20、$nextTick是什么?
vue实现响应式并不是数据发生变化后dom立即变化,而是按照一定的策略来进行dom更新。
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM
21、Vue子组件调用父组件的方法
- 第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法
- 第二种方法是在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了。
22、Promise对象是什么?
- 1.Promise是异步编程的一种解决方案,它是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。promise对象是一个构造函数,用来生成Promise实例;
- 2.promise的两个特点 对象状态不受外界影响 && 一旦状态改变,就不会再变,任何时候都可以得到结果(pending状态-->fulfilled || pending-->rejected)
23、axios的特点有哪些?
- 1、axios是一个基于promise的HTTP库,支持promise的所有API;
- 2、它可以拦截请求和响应;
- 3、它可以转换请求数据和响应数据,并对响应回来的内容自动转换为json类型的数据;
- 4、它安全性更高,客户端支持防御XSRF;
24、vue中的 ref 是什么?
ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。
25、vue如何兼容ie
babel-polyfill插件
26、页面刷新vuex被清空解决办法?
1.localStorage 存储到本地再回去
2.重新获取接口获取数据
27、Vue与Angular以及React的区别?
1.与AngularJS的区别
相同点:
都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。
不同点:
AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。
2.与React的区别
相同点:
React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用;中心思想相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数,可以让开发者定制化地去处理需求;都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性。
不同点:
React采用的Virtual DOM会对渲染出来的结果做脏检查;Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作Virtual DOM。
28、localstorage和sessionstorage是什么?区别是什么?
localstorage和sessionstorage一样都是用来存储客户端临时信息的对象,他们均只能存储字符串类型对象
localstorage生命周期是永久的,这意味着除非用户在浏览器提供的UI上清除localstorage信息,否则这些信息将永远存在。
sessionstorage生命周期为当前窗口或标签,一旦窗口或标签被永久关闭了,那么所有通过sessionstorage存储的数据也将被清空。
不同浏览器无法共享localstorage或sessionstorage中的信息。相同浏览器的不同页面可以共享相同的localstorage(页面属于相同的域名和端口),但是不同页面或标签间无法共享sessionstorage。这里需要注意的是,页面及标签仅指顶级窗口,如果一个标签页包含多个iframe标签他们属于同源页面,那么他们之间是可以共享sessionstorage的。
29、为什么要进行前后端分离?前后端分离的优势在哪里?劣势在哪里?
优点:前端专门负责前端页面和特效的编写,后端专门负责后端业务逻辑的处理,前端追求的是页面美观、页面流畅、页面兼容等。后端追求的是三高(高并发、高可用、高性能)让他们各自负责各自的领域,让专业的人负责处理专业的事情,提高开发效率
缺点:1 、当接口发生改变的时候,前后端都需要改变
2、 当发生异常的时候,前后端需要联调--联调是非常浪费时间的