Skip to main content

VUE基础

冻结属性 Object.freeze(data);

app.key = value;的方式进行响应式修改数据

app.$watch(key, function(old.new))添加数据监听

输入html片段 使用指令v-html

响应式数据 数据驱动模板

v-bind:attr绑定html属性到标签带上,可以实现动态绑定,如果固定的绑定可以直接设置属性

模板解析支持表达式的逻辑运算,三目运算,连字符,数学运算,函数调用等等

方法绑定 v-on:click="function",简写方式@click="function"

样式绑定v-bind:style,简写方式:class :style可以忽略v-bind,控制class是否应用:class="{divClass:false,spanClass:true}",支持数组的写法:class="[divClass, spanClass]"

编译时&运行时

  • 完整版:同时包含编译器和运行时的版本。
  • 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
  • 运行时:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。

如果需要在客户端编译模板,比如传入字符串给template选项,或挂载到一个元素上并以其DOM内部的h作为模板,就需要加编译器,style内联样式绑定,支持对象和数组的方式数组是对象方式的集合,key支持驼峰命名的编写方式,也支持短斜杠的链接方式需添加引号,

// 需要编译器
new Vue({
template: '<div>{{ hi }}</div>'
})

// 不需要编译器
new Vue({
render (h) {
return h('div', this.hi)
}
})

当使用vue-loader或vueify的时候,*.vue文件内部的模板会在构建时预编译成javascript,最终打好的包实际上是不需要编译器的,所以只用运行时版本即可比完整版本小30%,如果非要用完整版本

webpack

module.exports = {
// ...
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 时需用 'vue/dist/vue.common.js'
}
}
}

Rollup

const alias = require('rollup-plugin-alias')

rollup({
// ...
plugins: [
alias({
'vue': require.resolve('vue/dist/vue.esm.js')
})
]
})

vue对象

所有的vue组件都是vue实例,并且接受相同的选项对象

Vue实例暴露了一些有用的实例property与方法,以前缀¥开头,以便区分用户定义的property

  • vm.$data
  • vm.$el
  • vm.$watch('a',function)
生命周期

生命周期钩子中,this指向调用它的vue实例,

计算属性&监听属性&方法

计算属性,依赖的值进行修改,那么数据会进行修改,如果是其他的值进行修改会从缓存中读取数据

函数的方式绑定计算属性,每次都会计算,非依赖的数据发生变化也会触发修改,方法计算没有缓存,一对多推荐

监听属性,监听data中的值变化,根据key区别,如果需要监听多个值的变化需要分别填写,也是存在缓存,多对一推荐

v-if和v-show

惰性:初始条件为false不会渲染

v-if、v-elseif、v-else,需要连着写才能正常解析,多个标签的显示和隐藏使用<template>标签包裹不支持使用v-show,v-show需要使用dom标签的显示异常

v-for

for in

vue不能将检测到数组下标的更改,通过数组下标进行添加和更高都不能触发

对象的数据更新,如果后添加的一些数据,不能触发响应式

this.$set(this.dataArr, 0 {});修改数组并且触发响应式的方法

变异方法push、pop、shift、unshift方法也都会触发响应式

object.assign可以添加多个属性到响应式

v-for的优先级高于v-if,不建议在v-for中使用v-if,如果同时访问一个数据就存在优先级问题

==使用计算属性对数据进行过滤,源头进行修改数据,防止v-for和v-if同时使用==

事件处理

v-on:eventKey

:eventKey

.stop .self .once .prevent

@click默认添加了阻止默认操作

input回车提交 v-on:keyup.enter v-on:keyup.tab v-on:keyup.esc v-on:keyup.up 添加事件监听

自定义键盘码 Vue.config.keyCode.xxx = 87; v-on:keyup.xxx

表单绑定

input

textarea

select

radio

checkbox

v-model指令,创建双向数据绑定

自身标签的value属性设置后不起作用

checkbox可以绑定为数组中的值,自动识别添加到数组中

checkbox和radio需要设置value值

select第一个值一般用于给用户设置提示“请选择”,设置为disable属性,多选multiple属性,v-model值绑定为数组

修饰符

v-model.lazy=""

  • .lazy,失去焦点的时候触发
  • .number用户输入自动转换为数字类型
  • .trim

组件基础

创建全局

可服用vue实例

Vue.comonent("name", {
data:function(){
return {

}
},
template: '',
methods:{

},
watch{

},
computed:{

},
beforeCreated(){

},
created(){

},
destroyed(){

}
})

html中大小写不明感,所以使用小写加短横线的方式命名

注册组件的时候可以使用驼峰命名或者端横岗链接的方式,使用的时候只能使用短横杠链接的方式

数据传递,单向数据流 props:[]

父级v-bind:xxx-xxx="",子组件可以使用驼峰命名法进行获取

局部组件

const inputItem = {
data:function(){
return {

}
},
template:''
}

在vue的components属性中引入

全局组件就算不使用也会打入包中

组件通讯

父传子

v-bind属性绑定,子组件props:[]获取 this.$parent获取到父级的实例,可以调用父级的属性和方法

子传父

#emit事件监听传值,父组件中v-on:监听的事件 $child

兄弟组件

bus中央事件总线,非空的vue实例作为中央事件,结合实例方法$on $emit

Vue.property.$bus = new Vue();

//子组件发送
this.$bus.$emit('sendMsg', this.message);

//兄弟节点接受
this.$bus.$on('sendMsg', data => {

});

注册的$bus要及时销毁

import Vue from 'vue';
const Bus = new Vue();

data:{
Bus
}

将bus挂载到Vue根对象上

推荐使用

import Vue from 'vue';
const Bus = new Vue();
export default Bus;
那个页面需要使用就引入
vuex

管理所有组建的状态,状态管理模块

深层次嵌套

依赖注入的方式,不推荐直接用于应用程序代码中,建议在库和高阶组件中使用

父组件provied 子组件中通过inject获取

$attr/inheriAttrs,父组件通过属性传递,子组件通过$attr获取,需要逐层传递,根节点设置inheriAttrs为fasle 属性值就不会显示在dom节点上

组件深入

插槽

普通插槽

slot 占位符的作用

父组件给子组件传递组件后者dom节点

<slot>默认值!</slot>
具名插槽

v-slot指令配合name属性使用

想要按照自定义的位置显示父级传递过来的dom或者组件

<child>
<template v-slot:header><p></p></template>
</child>


<div>
<slot name="header"></slot>
</div>

具名插槽会放置到固定的位置,不具名的插槽默认插入数据

可以自定义默认插槽

<temolate v-slot:default></template>
作用域插槽

让插槽内容可以访问到子组件中才有的数据

子组件中定义的数据,父组件中使用插槽,在插槽中使用子组件定义的数据

<child>
<template v-slot:header="slotProps"><p>{{slotProps.lastName}}</p></template>
</child>


<div>
<slot name="header">{{'默认值'}}</slot>
</div>

注意:

  • 默认插槽如果需要拿数据,在组件的属性上填写v-slot="",如果存在具名插槽,默认的插槽就不能略写
动态切换组件
<component v-bind:is="component-name"></component>

动态组件状态缓存,keep-alive

使用keep-alive包过就可以实现组件状态缓存-实际缓存的是虚拟dom

过度动画

transtion标签

<transition name="">
<p v-show="isShow"></p>
</transition>


name-enter-active,name-leave-to{}

进入状态
.xx-enter{

}

.xx-enter-to{

}


离开状态
.xx-leave{

}

.xx-leave-to{

}

//如上写法繁琐,可以简写
name-enter-active,name-leave-to{}
.xx-enter,.xx-leave-to{

}

name会自动添加两个类name-enter-active name-leave-to

p元素显示或隐藏以后会移除对应的两个class

这来跟类可以自己定义类里面的效果内容

设置CSS动画

推荐的方式

@keyframes bounce-in{
0%{
transform:scale(0)
}
50%{
transform:scale(1.5)
}
100%{
transform:scale(1)
}
}

@keyframes bounce-out{
0%{
transform:scale(1)
}
50%{
transform:scale(1.5)
}
100%{
transform:scale(0)
}
}

.xxx-entry-active{
animation: bounce-in 2s linear
}

.xxx-entry-leave{
animation: bounce-out 2s linear
}

可以自定义过度类名,配合第三方库使用

<transition enter-active-class="animaited tade" leave-active-class="animaited tade">
<p v-show="isShow"></p>
</transition>

通过属性设置

多个元素过度:渲染后内部职能有一个子元素

当有相同的元素名进行切换,需要设置key属性进行唯一标记

过度模式:默认是元素进入离开同时发生,设置mode属性in-out新元素先进行过度完成之后当前元素过度离开,out-in当前元素先过度完成之后新元素过度进入

js动画库

钩子函数

<template 
@before-enter=""
@enter="";
@after-enter="";
@before-leave="";
@leave="";
@after-leave="";>
</template>

Velocity

必须声明done钩子回调,否则过度会立即完成

appear也可以添加calss

appear-active-class

对列表进行过度

transition-group以一个真实元素进行渲染

<transition-group
name="bounce"
tag="div"

>

</transition-group>

vue会对元素进行复用,所以需要给列表添加key

指令

  • v-text更新文本
  • v-html
  • v-if v-else v-else-if
  • v-show
  • v-for
  • v-model
  • v-on
  • v-bind

自定义指令

//输入框页面加载获取焦点
Vue.directive("focus", {
inserted:function(){
//被插入父节点就会触发此钩子
el.focus();
}
})

//使用
v-focus

自定义指令钩子函数

  • bind 只会调用一次,当指令第一次绑定到元素的时候触发
  • inserted绑定元素插入父节点的时候调用
  • update节点更新时触发钩子
  • componentUpdate组件节点进行更新时候触发
  • unbind解绑,也只调用一次

function(el,binding,vnode,oldnode)参数

  • el指令绑定的元素
  • binding对象,name指令名称、value指令绑定名称、oldValue上一值,arg指令穿的参数v-focus:xx=""这里的xxx,modifiers v-focus.foo这里的foo,vnode虚拟节点,oldNode update和componentUpdate中才有

vue3变化

  • 速度更快

  • 体积更小

  • 更易于维护

  • 更面向原生开发

  • 更易于开发使用

  • 虚拟DOM重写

  • 优化插槽生成

  • 静态树提升

  • 静态属性提升

  • 基于Proxy的观察者机制

  • 从flow转向type

  • 解耦,使内容更加模块化

  • 编译器重写

  • 运行时与平台无关

Vue cli创建项目

node_module->@vue->cli-service->webpack.config.js

可以在根目录下新增vue.config.js会自动进行合并,文件下的configureWebpack对象下配置

需要注意:输出路径等

查看配置:npx vue-cli-service inspect --mode peoduction

npx vue-cli-service inspect --mode peoduction >> xxx输出到文件中进行查看

vue-router

route

routes

router

onhashchange hash模式

history pushState replaceState

兜底路由全匹配,放到路由集合的最下面,设置redirect重定向到起码路由

$router.params.name获取路由参数

vue如果只是修改小部分,路由被重新触发可能不会引起页面生命周期重新触发

页面中添加路由变化

watch:{
$route(from,to){

}
}

路由嵌套

children属性设置

编程式导航

标签导航

路由导航this.$router.push()/replace(); this.$router.go()

命名路由,可以通过名称进行访问

push可以接受对相爱你给参数设置name属性也可以实现同样会的效果

路由传参{name:'',query:{}},使用params传值就使用params获取,使用query传值就使用query取值

传参有区别,一个会显示在地址栏一个不会显示在地址栏,不显示在地址栏进行刷新就会获取不到值

params类型传值,不建议使用path建议使用name进行路由配置

路由守卫

进入路由之前进行拦截检查

全局钩子函数

//首页new的router对象 router.boforeEach(to,form,next);

放行next()

阻止next(false);

重定向next('/login');

next(error) ->监听router.onError()

适合配置权限使用,权限控制

可以通过全局钩子每次跳转后都将滚动条滚动到起始window.scrollTo(0,0);

也可以打印log信息

组件内钩子函数

beforRouteEnter(to,from,next)//不能使用this,组件还没创建 beforRouteUpdate(to,from,next) beforRouteLeave(to,from,next)

可以在导航完成之前获取数据 执行next进入路由,缺点是用户会停留在前一个页面

导航完成之后获取路由就可以使用组件的生命周期实现

Vuex

状态管理模式

通过规则进行获取和修改数据,达到数据状态可追踪,可预测

import Vue form 'vue';
imnpoet Vuex from 'vuex';

//注册
Vue.use(Vuex);
const moduleA = {
state:{},
motations:{},
actions:{},
...
}
const moduleB = {
state:{},
motations:{},
actions:{},
...
}
export default new Vuex.Store({
//添加属性后所有的action motations等变成了局部 dispatch触发的时候就需要使用传值路径为m2/modifyName
namespace:true,
state:{
//状态数据
list:[1,2,3,4,5,6,7,8,9,10]
},
motations:{
//唯一改变state的方式

add(state){
return state.count++;
},
reduce(state){
return state.count--;
},

//支持设置未存在的值,加入响应式
addNewState(state){
//方式一
Vue.set(state, 'newState', '我是新添加的值');
//方式二
this.replaceState({...state,newState:'新添加的值'});
},
changeCount(state, newState){
Vue.set(state, 'newState', '新值');
}
},
actions:{
//异步操作
modifyCount(context, newValue){
setTimeout(() => {
context.commit('changeCount',{count:200});
});
}
},
modules:{
//模块化操作
//所有的数据都放在一个state中,随着项目体量增大,会造成代码可读性下降,所以需要模块化的管理
m1:moduleA,
m2:moduleB
},
getter:{
//compute计算属性,可以先对数据进行计算,主要是对状态处理
filterList(state){
return state.list.filter(n => n%2 === 0);
}
}
});

//根实例进行注册
new Vue({
router,
store,
render:h=>h(App)
}).$mount('#app');


//组件中使用
//在计算属性中使用可以实时监听到数据的变化
import {mapState, mapGetters,mapMutations,mapActions} from 'vuex';
compute:{
//使用辅助函数
...mapState(['count']);//推荐书写
//可以使用别名
//...mapState({c:'count', newValue:state=>state.newValue ? state.newValue : '我是默认值'});//推荐书写
//count(){
// this.$store.state.count
//}

...mapActions({handleAction:'modifyCount'}),


...mapGetters(['filterList'])
//可以定义别名
//...mapGetters({arr:'filterList'})

//getArr(){
// this.$store.filters.filterList
// }

//获取模块中的数据
moduleName(){
return this.$store.state.m1.name;
}
}

methods:{
add(){
//触发修改,可以传多个值
this.$store.commit('add',{});
},
handleChange(){
this.$store.dispatch('modifyCount');
}
}


模块可以进行嵌套 访问可以通过路径查询m1/m2/xxx

在模块化的基础上,设置了命名空间,如果想要访问全局的一些 action和mutations

//actions
dispatch('modifyCount', null, {root:true});
//mutations
commit('changeCount', null, {root:true});
//getter
get(state,getter,rootState,rootGetters){};

https://vuex.vuejs.org/zh/guide/modules.html