VUE
Vue :数据驱动的M V Vm框架
m :model(后台提供数据),v :view(页面),vM(模板)
-
流程
- m-》vm-》v
- m与vm之间通过ajax axios实现数据交互(前后端数据交互)
- vm(前端拿到数据后,对数据进行处理)
- v(数据改变后,页面改变)
-
兼容
- ie9及其以上(Vue使用Es5)
- ie8用的是es3
-
注意
- 不要将body、html作为挂载点
- 新建一个div作为挂载点
- 一个页面中尽量只有一个挂载点
- 插值等同
{{}}
({{}}
,只能与标签内使用) - 等同于innerHTML,innerTEXT
- 慎用innerHTML(会执行之内的代码->xxs攻击)
- 指令需要放在标签的属性中使用
- 指令中的双引号会提供一个js运行环境("变量、简单运算")双大括号
{{}}
具有相同的功能 - v-text插入的变量作为字符串处理
- v-html除非是信任的内容不然不要使用
-
v-show控制元素的显示隐藏
- 初始开销较大,dom一直存在与结构中 如果是需要经常切换的dom 推荐使用该指令
- v-show只是css级别的显示隐藏=》display:none
- 在vue中想要显示或隐藏
- 给data中添加一个属性,其值为布尔类型
- 将对应值添加个v-show指令
- 控制这个布尔值,以达到控制显示隐藏的目的
- true==显示,flse==隐藏
-
v-if
- 切换开销较大 false情况下 dom不会被渲染
- v-if是html结构级别的隐藏,直接将对应标签删除
- v-if、v-else-if、v-else和js中的if else else if一样的(只能满足一级要求,其后不再执行)
-
v-for
- 用于遍历数组或对象
- v-for="item in items"
- v-for="item,index in items" 项+索引 数组
- v-for="value in items" 值 对象
- v-for="value,key in items" 键+值 对象
- v-for="value,key,index in items" 键+值+索引 对象
- v-for="自定义名字 数组名"
- v-for可以遍历出index
- 对象遍历(不常用)
- v-for="value in 对象名"
- v-for="(value,key) in 对象名"
- v-for="(value,key,index) in 对象名"
- 要遍历那个标签就将指令写给那个标签
- 建议所有使用v-for指令的标签都添加上:key="惟一值"(后期使用,不建议使用index(虽然也是唯一的))
- key vue渲染原理 复用元素 没有key的话 当数据顺序发生变化时 如果没有绑定key 只会更新数据(元素不会更新,dom复用)
- 不建议同时使用v-for和v-if v-for拥有更高的优先级
-
v-bind:绑定
- 根据数据改变标签的属性(src,href)
- 将标签的属性与data中的变量绑定
- v-bind:src="data中的变量名"(将src与data中对应的变量名绑定,当数据改变时,src中的值也随之改变)
- 使用非常广泛=》简写成为:属性名="data中的变量"
- 如果要修改标签中的所有属性,可以绑定data中的对象,对象中的属性名,与标签中的属性一一对应(也可以添加其他属性)(可以更方便快捷的改变标签中的多个属性,或添加属性)
- :style=""->改变标签css样式
- 阔以是对象,但是值必须加引号(指令双引号间为js执行环境)
- :class=""->添加类名
- :class="[box,box1,{box2:flag}]"
- :class="{class:flag}"
- 绑定类名可以与普通class属性共存
<span class="class1" :class="{class2:flag1}"></span>
-
v-model:双向绑定
- 上述方法只能实现,数据改变之后,页面内容随之改变,但数据不会在页面内容改变之后随之改变(即单项绑定)
- 页面内容改变是(form表单元素),Vue数据改变
<input type="radio" v-model="" v-bind:value="0">
- 将input中的值value绑定为数字0,(指令中的双引号间为js运行环境),再将input与Vue中的数据,双向绑定,其后可以得到值为数字Number类型
-
v-on:绑定事件
- v-on后跟事件名,等于函数名(methods对象中的方法),有实参加括号,无实参可省略括号
- 可以通过this.data中的属性名,获取对应的数据
-
v-on:click=""
,双引号中可直接对data中的数据进行修改 -
v-on:click="methods方法名"
,由于使用较多,所以向v-bind一样具有缩写,@click="函数名(实参)"
-
修饰符
-
v-on:click="methods
中的方法名"==@click="methods中的方法名" - 事件触发具有冒泡机制,如何禁止-》修饰符
- @click.stop=""=>阻止冒泡
- @click.prevent=""=>阻止浏览器默认行为
-
三了解
-
v-pre:跳过标签编译过程,提升性能
`<pre>` 内部代码 回车 浏览器编译后 就是回车 `</pre>`
-
v-clock
```<style> [v-clock] { display:none } </style> ```
- 加载完成之前,具有v-clock的标签隐藏
- Vue编译完成之后,自动清楚v-clock
-
v-once
- 只在页面第一次渲染是调用数据
- 之后不会在跟随数据发生变化
生命周期
四大生命周期
- 顺序(钩子函数的执行顺序,与data同级)
- 创建-create
- beforeCreate:创建前(无data中的数据,只有该阶段无法访问到data中的数据)(数据于创建完成之后进行初始化)
- created:创建完成后
- 挂载-
mount(app.$mount(""))(不用el:"#app"挂载的话,可以用$mount挂载)
- beforeMount:挂载之前
- mounted:挂载之后
- 更新-update(数据发生改变)
- beforeUpdate:更新之前
- updated:更新之后
- 销毁-destroy
- beforeDestroy:销毁之前(app.$destroy()强制销毁)
- destroyed:销毁之后
- 创建-create
- 注意
- 创建和挂载的四个钩子函数只会调用一次
- 更新周期对应的两个钩子函数,只要数据发生改变就会触发
- data
- vue中的数据时响应式的 所以需要在初始化Vue是将需要响应的变量提前声明
- Object.freeze()
- 属性放进去,vue不会对其进行追踪变化了
- v-once
- 执行一次性的插值 数据改变时,插值处的内容不在更行
计算属性-computed(对象与data同级)
- 当遇到比较复杂的语句时,可将其写在computed中
- computed中的函数不可以调用,而是将其函数名写在{{中}},将其作为data中的属性名
- 创建时与methods一致,用法与data中的数据一致,对象!!!!
- 实质:将computed计算的结果return到页面中**
- 当多次调用同一个computed方法时,会存在缓存问题**,当需要实时更新数据时,可以使用methods(避免缓存)
监听-watch(对象与data同级)
- watch:
{要监听的值的名字(){},要监听的值的名字:{handler(){},deep:true,//可以监听对象内部属性的改变 immediate:true//页面加载后立马执行第一次监听函数}}
data:{
},
watch:{
//第一种方法(无法监听到对象内部数据变化)
msg(newValue,oldValue){
//data中的属性名+()+{},如果msg是对象的话,无法监听对象内属性的变化
//监听函数有两个参数,分别为新值和旧值
console.log(newValue,oldValue)
//该方法无法监听到对象中的数据,只能在变量内存储的地址发生改变时触发(引用类型,栈中存放的是指针,堆中的地址)
}
//第二种方法(第一种方法的变形)
msg:{
handler(newValue,oldValue){
console.log(newValue,oldValue)//data中的非对象数据,能够监听变化,并且存在两个数据,即新数据,旧数据
//仍然监听不到对象中数据的变化
}
}
//第三种方法(添加对应参数)
msg:{
handler(){
console.log("发生了变化")
},
deep:true, //是否监听对象内部数据的变化
immediate:true //是否与数据初始化之前设置监听函数
}
}
(详见)[https://cn.vuejs.org/v2/guide/list.html]
/*
由于 JavaScript 的限制,Vue 不能检测以下数组的变动:
当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
----vm.items[indexOfItem] = newValue
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
Vue 不能检测对象属性的添加或删除
*/
过滤器-filters(对象,data同级)
过滤器的应用范围
- 双花括号插值和v-bind表达式
- 过滤器的作用是,对对应的值进行处理-
{{数据 | 过滤器名}}
-
v-bind可以添加,
{{可以添加}}
,v-text不可以添加 - 过滤器函数中的参数就是 | 之前的对应的数据,过滤器函数中需要返回新的内容才能显示在页面中(即,过滤器函数中需要存在return)
- 过滤器可以用多个
{{数据 | 过滤器1 | 过滤器2 | 过滤器n}}
--(过滤器的添加顺序不同(对数据的处理顺序不同,可能造成,处理后数据结果不同))
组件
- 创建
- complate组件模板
- vue组件分为两种,一种为全局组件,一种为局部组件,组件需要注册才能使用
- 注册:Vue.component("组件名",组件配置对象)---》一般将 组件配置对象提取出来,外部配置
- 使用组件
- 要在父组件的组件模板中使用对应的组件标签
- <组件名></组件名>
- 局部注册
- 局部注册需要在对应组件中添加components属性
const 组件名={
template:"",
components:{
局部组件名:组件配置对象//这个组件就只能在当前组件的模板中使用
//相当与在对应父元素组件中实现注册,为局部组件,只能在该组件中调用,否则报错
}
}
- 注意
- 组件模板中只能有一个根节点
- 组建的配置对象,一定、一定、一定要放在其注册之前
- 组件中可以写出el对象外的几乎所有属性
- 组件中的data为函数,需要将数据return出去,然后可以正常使用,其他无异常
- 可以通过将组件标签,添加到其父组件的complate中,实现
- 往组件中添加数据,只能在其对应的complate中添加,在html结构标签中无法添加内容&&将其添加到其父元素的complate中后无法修改其数据
- 因为HTML不区分大小写,所以在HTMl模板中,标签需要写成纯小写,驼峰命名变成-连字符连接
通信方式
-
父子通信
- 父->子
-
父子组件通信基本步骤
- 在子组件中添加props(对象)
配置对应prop的名字 - 找到对应父组件模板中的子组件标签
在标签上添加对应prop的名字作为属性 后边跟着要传递的值
第二步可以传递静态值(固定值) 也可以传递动态值,data中的值
区别就在于加不加v-bind- 注意
props:["prop名1","prop名2",……]---》第一种写法,可以有多个prop,即数据通路
props:
{prop名字:String}/props:{prop名字:[String,Number]}-->即允许传输的数据类型,可以有多个
-
props:
{prop名字:{type:允许类型,default:默认值,validator(value){验证数据,true//验证通过,否则报错},required:true}}---->type(允许传输的数据类型),default(无传输数据时的默认值),validator(验证传输数据是否满足条件),required:true(true,则该项为必须传输项目)(与default有冲突,有默认项时,即使无数据传输,默认值将作为数据,是否必填无关紧要)
- 在子组件中添加props(对象)
props中的prop名,可以直接当做data中属性(数据)使用
遍历数组时,需要添加:key="惟一值即可"
-
- 子->父
- 父->子
-
非父子通信
main.js中 空vue载体 Vue.prototype.$bus=new Vue() 在所有的 Vue 实例中可用了,甚至在实例被创建之前就可以 $ 是在 Vue 所有实例中都可用的属性的一个简单约定。这样做会避免和已被定义的数据、方法、计算属性产生冲突。 通过 $ 为实例属性设置作用域来避免这种事情发生。你还可以根据你的喜好使用自己的约定,诸如 $_appName 或 ΩappName,来避免和插件或未来的插件相冲突。 需要进行通信的组件 import $bus from '../../../main'; this.$bus.$on('upload',payload=>{ do somthing }) //先监听 this.$bus.$emit('getPayload',payload) //后触发
修饰符
- 事件修饰符,为v-on提供了事件修饰符
- stop
- 阻止冒泡
- prevent
- 阻止默认行为
- capture
- 捕获阶段执行??
- self
- event.target 当前元素自身触发时执行函数
- once
- 只执行一次
- passive
- addEventListener(type,handler,useCapture)-->addEventListener(type,handler,{capture:false,passive:false,once:false})-->是否捕获,是否'顺从'???,是否只执行一次监听(之后自动removeEventListener)
- passive提高流畅性能
- 调用preventDefault()无效
- stop
- 按键修饰符,为v-on在监听键盘事件时添加按键修饰符
- enter .13
- tab
- delete
- esc
- space
- up
- down
- left
- right
- 可以通过全局config.keyCode对象自定义按键修饰符别名
- 系统修饰键,尽在按下相应按键时才触发鼠标或键盘事件的监听器
- ctrl
- alt
- shift
- meta
- exact修饰符允许你控制由精确的系统修饰符组合出发的事件,ctrl+shift等组合键
- 鼠标按钮修饰符
- left
- right
- middle
路由router
- 前后端都能够实现根据url的不同,跳转至指定页面,但实现原理不同
- 四步骤
- 一 创建组件配置对象
- 二 创建
routes
配置对象(必须是routes,否则虽然不报错,但是也不会有效果) - 三 创建
router
实例(new VueRouter) - 四 将router添加进Vue中
-
<router-view></router-view>
(url对应的组件,将替换掉该组件,即该组件不会显示到页面中)-
<router-link to="/" tag="li">
,该标签渲染到页面中时会被a
标签替换,to
中将会是替换后的url,tag
可以改变渲染后router-link
的结果(可以改变成为其他标签,通过js实现相应的链接跳转),激活状态的链接会具有router-link-active
(该类名不够精确)---》推荐使用router-link-exact-active
来为激活状态的标签添加对应的类名 -
linkExactActiveClass:'active'
,通过该全局配置,实现类名的替换var router=new VueRouter({//new VueRouter大括号中为全局配置 linkExactActiveClass})
- 点击对应
router-link
标签,to
到新的url后,显示对应的组件,实现页面的跳转(数据的改变)但域名不会改变
-
动态路由
-
- 配置路由时可以使用动态路由
{path:"/a/:id"}
- 通过
$route.params.id
来获取对应的id,根据id获取数据,并改变显示内容 - 通过为
$route
设置监听函数,来实现当url改变时,发送新的请求,获取数据后渲染到页面的操作,可以为其添加immediate属性,实现页面首次加载就发出请求 -
如果动态路由想要使用a标签跳转,必须给路由添加一个name属性并使用名字进行跳转
<router-link :to="{path: '/demo', params: {id: 1}}">链接</router-link>
- 配置路由时可以使用动态路由
-
- 使用?id=xx的形式--query
- 配置路由时使用基本配置方式
- 将query值添加到路由的最后使用?xx=值的形式添加?xx=值&xx=值
- 通过$route.query.xx来获取
动态路由与静态路由的区别
- 二者无实质区别(都是根据url不同,获取数据渲染到页面中)
- 获取方式的差别
- 动态路由获取--$route.params.xxx与配置对象中
routes[{path:"/:xxx"}]
--只需要xxx一致即可---当使用router-link :to="{name:'',params:{xxx:''}"
,只需要v-bind:to即可,否则获取到的是字符串--(需要使用name) - 静态路由--$route.query.xxx与链接中
router-link to="/?xxx=xx"
- 动态路由获取--$route.params.xxx与配置对象中
原理
- 通过切换url,获取数据,更换div中的内容
- 后端为主--原始模式
- 查找dns服务器,dns服务器返回对应的ip地址
- 根据ip地址找到服务器
- 服务器后台根据url提取数据
- 根据提取的数据去数据库中查找数据
- 将数据渲染到模板中的页面
- 返回浏览器
- 前端只负责提供静态页面模板,供后端渲染数据
- 前端为主--Vue--M、V、VM
- 查找 dns服务器,dns服务器返回对应的ip地址
- 根据ip地址找到服务器
- Vue根据传来的url提取数据
- Vue根据数据发送请求(ajax请求),将查询数据发送给后台
- 后台接受到数据后,查询数据,返回查询到的数据
- Vue接收到数据后,渲染到模板中
- 浏览器显示
- 优缺点
- 前端渲染
- 速度快,减轻服务器压力,交互较好(loading等),不借助某些技术无法进行seo优化
- 后端渲染
- 便于seo优化,访问到的内容都在页面中
- 前端渲染
动态路由
- 动态路由获取
- 模板中
- $route.params.x
- js
- this.$route.params.x
- watch
- to.params.x
- 模板中
- 重定向
- a跳转到b
- 给a设置
redirect
--》b的路由
- 给a设置
- a跳转到b
- 别名
- 当访问/a时,实际访问到的内容为b时,url显示为/a
- 应该给/b加
alias
"/a"
- 应该给/b加
- 当访问/a时,实际访问到的内容为b时,url显示为/a
- 命名视图
- 同级展示多个视图,而不是嵌套展示,可以使用命名视图
- 一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件
路由组件传参
- 在组件中使用$route会使之与对应路由形成高度耦合,从而使组件只能在某些特定的url上使用,限制了灵活性,可使用
props
将组件和路由解耦 -
{ path: '/user/:id', component: User, props: true }
routes中设置props为true时,默认传递$route.params- 组件配置对象中,可直接添加props属性,为其添加所需prop即可(如:id、tab等)
- 你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。
{ path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
- 该返回对象将作为属性,传递给对应组件
HTML5 History模式
- 使用history模式,可以使得URL像正常url(去掉#号)
导航守卫--》路由导航守卫--》路由钩子函数
- 所有的路由都会经过全局导航守卫,所以在网页需要登录等操作才能访问时使用**
-
this.$route.query.xxx
---->js函数中通过,获取url中查询字符串信息,此处为跳转至该页面的源页面 - 通过
this.$router.push(url)
---->实现跳转至来时页面---》即登录过后跳转至页面 -
router.beforeEach((to,from,next)=>{})
,(from来源,to去向,next守卫),to.fullPath
(其中存放着url路径及查询字符串) -
meta
属性routes
中添加对应属性,to.matched
其中存放着当前网页的路径,以及其祖先url信息,可在其中找到对应的meta,运用数组some
方法(存在该meta,即需要验证的页面)
全局解析守卫
- beforeEach**
- 类似router.beforeEach
- 区别,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
全局后置钩子
- afterEach((to,from)=>{})
- 只有to,from**,不接受next函数,也不会改变导航本身
路由独享守卫
- beforeEnter**
- 在路由配置(routes)上直接定义
- 与全局前置守卫的方法参数一样
组件内守卫
- beforeRouteEnter
- 在渲染该组件的对应路由被confirm前调用
- !不能 !获取组件实例
this
----可以通过beforeRouteEnter(to, from, next) { console.log(this, 'beforeRouteEnter'); // undefined console.log(to, '组件独享守卫beforeRouteEnter第一个参数'); console.log(from, '组件独享守卫beforeRouteEnter第二个参数'); console.log(next, '组件独享守卫beforeRouteEnter第三个参数'); next(vm => { //因为当钩子执行前,组件实例还没被创建 // vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。 console.log(vm);//当前组件的实例 }); }
---vm---vue官方使用--vue的实例---间接使用this
- beforeRouteUpdate--2.2新增
- 在当前路由改变,但是该组件被复用时调用--即虽然路由改变,但访问的仍然是同一个页面
- 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
- // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
- 可以访问组件实例
this
- beforeRouteLeave
- 导航离开该组件的对应路由时调用
- 可以访问组件实例
this
完整的导航解析流程--官方(并非所有步骤都会执行)
- 导航被触发
- 在失活的组件里调用离开守卫
- 调用全局的
beforeEach
守卫 - 在重用的组件里调用
veforeRouteUpdate
- 在路由配置里调用beforeEnter
- 解析异步路由组件
- 在被激活的组件里调用
beforeRouteEnter
- 调用全局的
beforeResolve
守卫 - 导航被确认
- 调用全局的
afterEach
钩子 - 触发DOM更新
- 用创建好的实例调用
beforeRouteEnter
守卫中传给next
的回调函数
守卫与生命周期钩子函数的执行顺序
- 全局 3
- beforeEach
- beforeResolve
- afterEach
- 路由独享 1
- beforeEnter
- 组件内 3
- beforeRouteEnter
- beforeRouteUpdate
- beforeRouteLeave
- 导航守卫和声明周期钩子函数的执行先后顺序
- 访问路由时
- 全局守卫beforeEach先执行
- 路由独享守卫beforeEnter执行
- 组件内守卫beforeRouteEnter执行
- 全局解析守卫beforeResolve执行
- 最后全局后置守卫afterEach执行
- 声明周期钩子函数执行
- 访问路由时
-
切换路由时,如果路由是动态路由
- 全局守卫beforeEach调用
- 组件内守卫beforeRouteUpdate调用
- beforeResolve调用
- afterEach
- // 如果数据也发生了变化,在路由结束后触发
- beforeUpdate
- updated
-
切换路由时,路由不同
- from befreRouteLeave
- beforeEach
- to 路由独享守卫beforeEnter
- to 组件内守卫 beforeRouteEnter
- 全局解析守卫beforeResolve
- 全局后置守卫 afterEach
- to 组件生命周期钩子,知道to组件创建完成
- 销毁from的组件
- to 组件挂载
当组件切换时,先创建新组件,当新组件beforeMount(生命周期钩子函数-挂载前)之后,才销毁旧组件,旧组件销毁后,新组件被挂载
生命周期钩子函数永远在路由afterEach之后执行
过渡动效
- 过渡动效
- 为router-view标签,添加
transition
标签
- 为router-view标签,添加
- 单个路由的过渡
- 给路由组件设置过渡效果,路由组件内使用
transition
,并设置不同的name
属性
- 给路由组件设置过渡效果,路由组件内使用
- 基于路由的动态过渡
- 基于当前路由与目标路由的变化关系,动态设置过渡效果
- 基于路由变化使用对应的
name
值,实现路由不同,过渡效果的不同
- Vue在插入、更新或则移除DOM时**,提供多种不同方式的过渡效果
- 在css过渡和动画中自动应用class
- 配合使用第三方css动画库,如Animate.css
- 在过渡钩子函数中使用JavaScript直接操作DOM
- 配合使用第三方JavaScript动画库,如Velocity.js
- 单元素/组件的过渡
- 条件渲染(使用
v-if
) - 条件展示(使用
v-show
) - 动态组件
- 组件根节点
- 条件渲染(使用
- 当插入或删除包含在
transition
组件中的元素时- 自动嗅探目标元素是否应用了css过渡或动画,如果是,在恰当的时机添加/删除css类名
- 如果过渡组件提供了JavaScript钩子函数,这些钩子函数将在恰当的时机被调用
- 如果没有找到JavaScript钩子并且也没有检测到css过渡/动画,DOM操作(插入/删除)在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和Vue的
nextTick概念不同
)
- 类名-六个class
-
v-enter
:定义过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除 -
v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除,这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数 -
v-enter-to
:2.1.8版及以上定义进入过渡的结束状态,在元素被插入之后下一帧生效(于此同时v-enter
被移除),在过渡/动画完成之后移除 -
v-leave
:定义离开过渡的开始状态,在离开过渡被触发时立刻生效,下一帧被移除 -
v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数 -
v-leave-to
:2.1.8版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效(与此同时v-leave
被删除),在过渡/动画完成之后移除
- 对于这些过渡中切换的类名来说,如果使用一个没有名字的
<transition>
,则v-
是这些类名的默认前缀。如果使用了<transition name="my-transition">
,那么v-enter
会替换为my-transition-enter
,即替换为transition标签中的name属性的值
-
- 自定义过渡的类名
- enter-class === v-enter
- enter-active-class === v-enter-active
- enter-to-class === v-enter-to
- leave-class === v-leave
- leave-active-class === v-leave-active
- leave-to-class === v-leave-to
- 添加到transition标签中,修改对应类名
- 他们的优先级高于普通的类名,这对于Vue的过渡系统和其他第三方css动画库,如Animate.css结合使用十分有效
- 不再需要为transition标签添加name属性
- 同时使用过渡和动画
Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是 transitionend 或 animationend ,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。
但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,你就需要使用 type 特性并设置 animation 或 transition 来明确声明你需要 Vue 监听的类型
Vueg插件
- 为webApp提供转场特效的开源Vue插件
- Vueg
Vuex-状态管理模式
借鉴The Elm Architecture、Redux、Flux,与其他模式不同的是,Vuex是专门为Vue.js设计的状态管理库,以利用Vue.js的细粒度数据响应机制来进行高效的状态更新
-
什么情况下使用Vuex
- 如果不开发大型单页应用,使用Vuex可能是繁琐冗余的
- 如果应用够简单,最好不要使用Vuex,简单的store模式足够了
-
Vuex与单纯的全局对象的区别
- Vuex的状态存储是响应式的,当Vuex组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的得到高效更新
- 不能直接改变store中的状态,改变store中的状态的唯一途径就是显示的提交(commit)mutation,这样使得我们方便的追踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好的了解我们的应用
-
State
- 可以在需要使用store中数据的组件的computed中新建对应state中数据的方法,将state中的数据返回即可直接使用
computed:{msg(){return this.$store.state.xxx}}
- mapState-辅助函数
- 当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余,使用mapState辅助函数帮助我们生成计算属性
-
computed:mapState({count:state=>state.count,countAlias:"count"})
-->使用箭头函数可使代码更简练,但有时为能使用this
获取局部状态,必须使用常规函数--但是这种写发造成非store相关数据无法写入 - 对象展开运算符
- 使用对象展开运算符将此对象混入到外部对象中
computed:{localComputed(){},...mapState({})}
- 使用对象展开运算符将此对象混入到外部对象中
- 可以在需要使用store中数据的组件的computed中新建对应state中数据的方法,将state中的数据返回即可直接使用
-
Getter
- 从store的state中派生出一些状态
- getter接收
state
作为第一个参数,也可以接收其他getter作为第二个参数 - 通过让getter返回一个函数,实现getter传参,getter在通过方法访问时,每次都会进行调用,而不会缓存结果
-
Mutation--提交
-
更改Vuex的store中的状态的位移方法是提交mutation。Vuex中的mutation非常类似于事件,每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且会接受state作为第一个参数
- 触发。
this.$store.commit('xx')
- 提交载荷(payload)。
mutations:{xxx(state,n){}}
--state作为第一个参数,第二个参数为载荷,大多数情况下载荷应该是一个对象 - 对象风格的提交。
this.$store.commit({type:'xxx',cs:xx})
--type即为mutations中的事件名,其他均为参数
- 触发。
- Mutation需遵守Vue的响应规则
- 最好提前在store中初始化所有所需属性
- 当需要在对象上添加新属性时,应该:
- 使用
Vue.set(obj,'newProp',123),
或者 - 以新对象替换老对象。
state.obj={...state.obj,newProp:123}
- 使用
- 使用常量替代Mutation事件类型
- 使用常量替代mutation事件类型在各种Flux实现中是很常见的模式。这样可以使linter之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个app包含的mutation一目了然 ,--即将mutation中的事件名作为一个对象的属性存入对象中
[obj.name]
作为mutation中的事件名,可以更直观的了解各事件的功能
- 使用常量替代mutation事件类型在各种Flux实现中是很常见的模式。这样可以使linter之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个app包含的mutation一目了然 ,--即将mutation中的事件名作为一个对象的属性存入对象中
- Mutation必须是同步函数
- 在Vuex中,mutation都是同步事物
-
更改Vuex的store中的状态的位移方法是提交mutation。Vuex中的mutation非常类似于事件,每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且会接受state作为第一个参数
-
Action--分发
- Action类似于mutation,不同之处在于:
- Action提交的是mutation,而不是直接变更状态
- Action可以包含任意一步操作
-
actions:{xxx(context){context.commit('xxx')}}
--actions中处理的都是异步操作,改变数据时最后一步都是调用mtation即context.commit() - 使用参数解构/解构赋值来简化代码(特别是需要调用commit很多次的时候)--
actions:{xxx({commit}){commit('xxx')}}
--通过结构复制直接得到context中的commit调用mutation中对应的事件处理 - 触发
- this.$store.dispath('xxx')
- 因为mutation中只能执行同步操作,所以只能通过actions内部执行异步操作后调用mutation--
actions:{xx({commit}){setTimeout(()=>{commit('xxx')},1000)}}
--一秒后调用commit('xx')执行mutation中的对应处理事件 - Actions支持同样的载荷方式和对象方式进行分发
- Action类似于mutation,不同之处在于:
-
module
- 模块中有自己的state,将其放入store的modules中后,其state会变成rootState(最外层store中的state)
- this.$store.state.模块名 //这就是对应模块中的state对象
- getters最终会变成root中的getters
-
module={getters:{getter名字(state,getters,rootState,rootGetter){}}}
--state是当前模块的状态,rootState是根store的state - 如果没有
namespaced:true
属性那么getter就是rootstore的getter,如果有该属性getters就是模块中的getter,第四个参数rootGetter才是全局中全部的getter this.$store.getters.getter名字
- 如果给模块添加namespaced:true那么对应的getter,mutation,action都会变成“对应模块名/对应名字”--区分rootstore与模块中的getter,mutation,action
- 如果模块中有
namespaced
属性,那么commit('mutation')只能触发模块内的mutation- 如果在commit第三个参数中添加{root:true}-则触发的是全局的mutation--
commit('mutation名字',payload,{root:true})
--dispatch同理
- 如果在commit第三个参数中添加{root:true}-则触发的是全局的mutation--
- 模块创建
new Vuex.Store({modules:{模块名:{}}})
- 分开--
const module={} new Vuex.Store({modules:{模块名:module}})
- 模块中也有state,getters,mutations,actions,modules
-
单个模块当做一个store即可
- state
- this.$store.state
- 模块中的state
- this.$store.state.模块名
- 模块中的state
- this.$store.state
- getters,actions,mutations--直接会添加到rootstore中的对应位置
- 如果给模块添加namespaced:true
- name对应的getters,mutations,actions会变成 模块名/名字 的形式,并且可以与rootstore中的姓名重合,因为名字之前带有各自模块名
- 同时,直接在模块中commit('mutation')/dispatch('action'),默认提交/分发的是模块中的mutation/action
- 想要调用全局,需要在之后加上{root:true}
commit('mutation',payload,{root:true})
dispatch('action',payload,{root:true})
- name对应的getters,mutations,actions会变成 模块名/名字 的形式,并且可以与rootstore中的姓名重合,因为名字之前带有各自模块名
- 辅助函数如果想要使用命名空间模块中的内容
mapState({msg:state=>state.模块名.msg})
- mapState('模块名',['msg'])
- state
-
- 模块中有自己的state,将其放入store的modules中后,其state会变成rootState(最外层store中的state)
代码
var store = new Vuex.Store({
state:{
},
mutations:{
},
getters:{
},
actions:{
}
})
this.$store.state.xx //获取state中存储的数据
- input v-model处理方法**
- 详见Vuex-表单处理
- 当页面中存在input等表单元素时,需要使用
v-model
,但store中state无法与computed直接修改 - 所以将computed的书写格式写成
computed:{msg:{get(){//获得state中的数据},set(value){//value 当页面中form表单中的数据发生变化时触发,值即为修改后的数据 可在此提交mutation修改state中的对应数据 this.$store.commit('setMsg',value)}}}
- computed对象中的get方法用来获取store里state中的数据,显示到页面,而set方法中的value则为页面中表单数据发生变化后的值,可在触发后将值作为载荷提交mutation修改state中的数据
- axios拦截器**
- 在请求或响应被
then
或catch
处理前拦截它们 - 对发送前数据添加token,或设置请求头,验证等
- 对响应数据做处理,剥离外层结构等
- 在请求或响应被
//添加请求拦截器
axios.interceptors.request.use(function(config){
//在发送请求之前做些什么
return config;
},function(error){
//对请求错误做些什么
return Promise.reject(error);
});
// axios.interceptors.request.use(config=>config,error=>Promise.reject(error))
//添加响应拦截器
axios.interceptors.response.use(function(response){
//对响应数据做点什么
return response;
},function(error){
//对响应错误做点什么
return Promise.reject(error);
})
/*
axios.interceptors.response.use(response=>response,error=>Promise.reject(error))
*/
keep-alive
- 切换组件外层添加
<keep-alive></keep-alive>
可以缓存组件的状态,当再次切换后显示之前的状态--默认情况下组件被v-if
隐藏后经历destroy周期,再次显示时触发create,mount周期,不会保留之前的访问状态 - 属性
- include 符合条件的组件会被缓存
- 字符串
- 逗号隔开组件
- 正则
- 符合比正则表达式的会被缓存--v-bind:include
- 数组
- ['组件名','组件名']
- v-bind:include
- 字符串
- exclude与include相仿,符合条件的不会被缓存
- include 符合条件的组件会被缓存
- Props:
- include-字符串或正则表达式,只有匹配的组件会被缓存
- exclude-字符串或正则表达式,任何匹配的组件都不会被缓存
- 用法
-
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和<transition>
相似,<keep-alive>
是一个抽象的组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中。当组件在<keep-alive>
内被切换,它的activated
和deactivated
这两个声明周期钩子函数将会被对应的执行 - 主要用于保留组件状态或避免重新渲染
- include、exclude--匹配检查先检查组件自身的name选项,如果name选项不可用,则匹配他的局部注册名称(父组件components选项的键值)。匿名组件不能被匹配
- activated--
keep-alive
组件激活时调用 - deactivated--
keep-alive
组件停用时调用 - 由于
keep-alive
的组件缓存,切换组件时不会触发对应的destroy,create,mount周期函数
-
ref
- ref可以添加在组件或者html标签上
- 可以通过this.$refs.自定义名字获取
- created生命周期中无法获取DOM,因为created时页面还没有渲染
- ref加在html标签上,得到对应的DOM对象
- ref加载组件标签上,得到的是对应组件的组件对象
nextTick
this.$nextTick(()=>{//这里的代码会在每次更新后,页面DOM更新后才会触发})
对象操作
- 如果对象某个值不存在,先要添加新的值,并试数据响应--不能使用app.对象.新属性=值
- 需要使用Vue.set方法
- Vue.set(对象,'属性','值')
- app.$set(对象,'属性','值')
- Vue.delete(对象,'属性')
- Vue.$delete(对象,'属性')
自定义指令
- 想要对DOM元素进行原生操作时,可以使用自定义指令
Vue.directive('指令名(不加v-)',{})
- 自定义指令共5个钩子函数
- bind
- inserted
- update
- componentUpdated
- unbind
- 参数
- el 指令绑定的元素的DOM对象可以直接操作DOM
- binding
- name 指令名
- value 指令后等于的值 v-指令名='value'
- oldValue 仅在update和componentUpdated中存在
- expression 指令表达
- arg 参数 v-on:click click就是参数
- modifiers v-on:click.stop stop就是修饰符
- 修饰符可以有多个,所以修饰符是一个对象
- vnode Vue 产生的虚拟节点
- oldVnode 上一个虚拟节点
slot插槽
- 正常情况下
template
中,标签中的内容会被忽略,而slot标签相当于,预留的插槽,可以实现内容的正常显示 - 在两
slot
标签中的内容会被当做默认值,即当后期不插入内容时,显示默认值 - 优点:方便后期组件使用,和更改对应信息
具名插槽-name属性
- 当
slot
标签有多个时,为避免混乱,可以为其添加name属性 - 当使用时,可以在标签中添加
slot
属性,其值为对应slot名
-(造成多余标签) - 可以通过
<template slot="slotname"></template>
来实现,该标签不会显示在页面中
默认内容
- 当在
slot
标签之间填写内容时,会被当做默认内容,当不在组件标签之间填写内容时,显示默认内容,填写则覆盖默认值 - 具名标签
slot
标签之间添加默认内容无效 - 具名插槽会与具有
slot
属性的标签一一对应,多余的内容会在不具名slot
中统一显示,如果不存在该标签,则内容舍弃
作用域插槽(flot-scope="自定义名字")
改变从子组件获取的数据结构???
-
创建组件时
- 在slot标签上添加的属性
- <slot 数据名="值" 数据名2="值2"></slot>
- 使用组件时,会出现在组件标签内部的slot-scope上
<组件标签>- div slot-scope="自定义名字"">
- // 自定义名字就是一个对象,对象上包含了所有的slot标签上的属性
- /div>
- </组件标签>
-
作用域插槽的意义
- 将数据给对应的组件,让使用组件的人可以自定义组件的模板
@click==v-on:click
- 写在template中的v-on:click(click事件)可以正常触发
- 但是,当写在组件标签中时,会被当做是监听(自定义事件名)**
- 所以**,如果想要在组件标签中写@click事件,可以使用修饰符.native--》声明该click为原生click事件
- 或者在
template
中,为@click添加自定义事件,即子到父通信,可传递数据,否则无法触发click事件**
Element UI-》组件库
vue-cli
- 命令行工具
- Vue 提供了一个官方的 CLI,为单页面应用快速搭建 (SPA) 繁杂的脚手架。它为现代前端工作流提供了 batteries-included 的构建设置。只需要几分钟的时间就可以运行起来并带有热重载、保存时 lint 校验,以及生产环境可用的构建版本。更多详情可查阅 Vue CLI 的文档。
- 安装步骤
- cnpm install -g vue-cli--(全局安装vue-cli)
- vue init list name path--(初始化 vue init list(模板类型-通过vue-list查看) name(项目名) path(不写,默认为当前路径))
-
vue init webpack
+项目名称
(不能包含大写)
- 创建
? Project name 输入项目名称
? Project description 输入项目描述
? Author 作者
? Vue build 打包方式,回车就好了
? Install vue-router? 选择 Y 使用 vue-router,输入 N 不使用
? Use ESLint to lint your code? 代码规范,推荐 N
? Setup unit tests with Karma + Mocha? 单元测试,推荐 N
? Setup e2e tests with Nightwatch? E2E测试,N
- 运行
- 进入对应文件,路径
- cnpm install--(安装所需组件)
- npm start/npm run dev
- 编写
- sc--快捷生成template script style结构
- 插件
- Vetur