Vue基础

321 阅读2分钟

1.触发重排和重绘

  • 添加或删除可见DOM元素
  • 元素位置改变
  • 元素尺寸改变
  • DOM内容改变
  • 页面渲染初始化
  • 浏览器尺寸改变
  • css属性: offsetTop scrollTop clientTop getComputedStyle()

2.消耗的性能

操作DOM以及引起重排和重绘消耗CPU及GPU的性能,家用GPU图形能力天生不足。

3.Vue优点

  1. 性能好

    vue的核心是虚拟dom,在js层对比,只改变部分数据,使用虚拟dom可减少dom操作,从而提升性能。

  2. 视图、数据分离,提高开发效率。

  3. 维护成本低。

  4. 渐进式MVVM框架,适用性强。

4.vue特点

改数据是异步的,会在一段时间内把要更改的数据打包压入执行栈,一起执行。

5.vue基础

1.数组变异方法:

1.pop push shift unshift reverse sort splice

2.vm.$set(vm.array,idnex,value)

3.vue.set(vm.array,idnex,value)

通过数组index和length不能改变数组数据

2.对象数据改变方法:

var vm = new vue({
	el:'#app',
	data:{
	obj:{
        a:10
	}
}})
vm.$set(vm.obj,key,value)
vue.set(vm.obj,key,value)

3.vue指令

  1. v-once 只渲染为第一次获取的数据

  2. v-html 渲染html 注意避免XSS攻击

  3. <template v-if='flag'> </template> 条件渲染

  4. v-show 条件渲染 相当于改变display样式,适用于经常改变时使用。v-show 不支持template。

  5. v-bind:src='' v-bind:class='' 绑定属性 可简写 为 :src='' :classs=['','' :style= 'styleobj']

  6. v-on:click 绑定事件 简写 @click

  7. 列表循环

    v-for="(item,index)in list" :key='index' 
    <template></template>上不能写key值 应该写在里面的结构上
    
  8. v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定

  9. 自定义指令

    Vue.directive('slice',{  //全局自定义指令
        bind(el,bingings,vnode){
    		el//绑定的dom节点
    		bingings//绑定的信息
    		//vnode//虚拟节点
        },
        update(el,bindings,vnode){
    
        },
        inserted(el,bindings,vnode){
    
        }
    })
    

4. 过滤器 filter

Vue.filter('filterName' (val)=>{
    return val.toLocaleString();
})
<div>{{money | filterName }}</div>
filter 可串联使用多个

5.挂载

el=> $mount=>template=>找到对应dom的outhtml作为模板,生成AST,再利用render函数生成虚拟dom,然后替换原来的dom;
有template优先使用template。
有定义render函数时会执行定义的函数 

6.生命周期

avatar

7.计算属性/侦听器/methods

computed :

1.只有涉及的数据发生改变时才会触发computed中的函数。

2.计算属性可以观察多个数据,其中一个改变就会触发重新渲染。

3.计算属性可以返回新数据。

4.计算属性不可执行异步任务。

watch:

1.第一次不会执行watch中的函数,在监听的对象中加上immediate:true 就会触发第一次渲染执行该函数。

2.一个函数只能监听一个数据的改变。

3.侦听器只能观察原始的数据。

4.侦听器可以执行异步任务。

methods:页面渲染就会触发methods函数。

6.组件

1.全局组件

Vue.component('hello-world',{
	template:'<div>hello world</div>' ,//组件定义
    data(){}//组件中data要写成函数形式
})

<div id = 'app'>
    <hello-world></hello-world>  //使用组件尽量使用连字符命名
</div>

2.局部组件

new Vue({
    el:'#app',
    data:{},
    component:{  //局部组件需写在component中
        hello-world:{
            template:'<div>hello world</div>' ,//组件定义
            data(){
                return{
					msg:'hello world'
				}
            }
        }
    }
})

<div id = 'app'>
    <hello-world></hello-world>  //使用组件尽量使用连字符命名
</div>

3.父子组件传值

new Vue({
    el:'#app',
    data:{},
    component:{//局部组件需写在component中
        props:{
            a:{
                type:'String',  //类型
                default:'hello wrold', //默认值
                required:true  //必须
            },
            b:{
                type:'Array',
                default:()=>{
                    return [1,2,3] //引用值需写成函数形式封闭作用域
                },
                required:true
            },
            title:{
			   type:'Number',
                default:10,
                required:true,
            	validator(value){  //传值校验
        	return value>10
   		 	}
        }
      } //父组件传值给子组件,子组件需在props中定义
        hello-world:{
            template:'<div> 
       				 <p> a + b </p>
        			</div>' 
        }
    }
})

<div id = 'app'>
    <hello-world a='1' b ='2'></hello-world>  //使用组件尽量使用连字符命名
</div>

4. 父向子传值方式

  1. 父子组件推荐采用props特性传值

    v-bind ='$attrs' //在子组件中绑定子组件中未定义的属性,传给孙组件、inheritAttrs:false //不在行间显示

  2. vm.$parent vm.$children 父子组件数据 不常用

  3. provide inject 不常用

5.子向父传值

Vue.component('welcome-button', {
  template: `
    <button v-on:click="$emit('welcome')">
      Click me to be welcomed
    </button>
  `
})
<div id="emit-example-simple">
  <welcome-button v-on:welcome="sayHi"></welcome-button>
</div>
new Vue({
  el: '#emit-example-simple',
  methods: {
    sayHi: function () {
      alert('Hi!')
    }
  }
})

6.事件总线

    Vue.prototype.bus = new Vue();
    const vm = new Vue({
      el: '#app',
      components: {
          
        myComponent: {
          data() {
            return {
              content: ''
            }
          },
          created() {
            this.bus.$on('clickevent', content => { //订阅clickevent事件
              this.content = content;
            })
          },
          template: `<div>{{content}}</div>`
        },
                    
        
        myInput: {
          data() {
            return {
              inputval: ''
            }
          },
          methods: {
            handleClick() {
              this.bus.$emit('clickevent', this.inputval) //发布clickevent事件
            }
          },
          template: `<div>
                    <input  type='text' v-model.lazy='inputval'/>
                    <button @click = 'handleClick'>提交</button>
                    </div>`
        }
      }

    })

7.vue-router

import Vue from 'vue'
import Router from 'vue-router'
import defaultPage from '@/layout/default'
import index from '@/page/index'

Vue.use(Router)

export default new Router({
  mode:'history',
  linkExactActiveClass:'exact', //精准匹配
  linkActiveClass:'active',//  模糊匹配 包含父路由
  routes: [{
    path: '/',
    name: 'default',
    component: defaultPage,
    redirect: '/index',  //重定向  进入/路径时默认转到/index页
    children: [{
      path: '/index',
      name: 'index',
      component: index
    }, {
      path: '/changeCity',
      name: 'changeCity',
      component: () => import('@/page/changeCity')
    }, {
      path: 'goods/:name',
      name: 'goods',
      component: () => import('@/page/goodsList')
    }]
  },
  {
    path: '/blank',
    name: 'blankpage',
    component: () => import('@/layout/blank'),
    children: [{
      path: '/login',
      name: 'login',
      component: () => import('@/page/login')
    },
    {
      path: '/register',
      name: 'register',
      component: () => import('@/page/register')
    }
    ]
  }
  ]
})

1.路由跳转

<router-link tag='li' :to="{name:'login'}">登录</router-link>

<router-view></router-view>//组件显示区

路由跳转 事件中 this.$router.push('/home')或 this.$router.replace('/home');

2. 动态路由

<router-link tag='li' :to="{name:'question',params:{id:questionId}}">问题</router-link>

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

3.导航守卫

组件内守卫
beforeRouteLeave(to,from,next){
    if(this.name){
        const flag = window.confirm('你确定要离开吗?')
        if(flag){
            this.name = '';
            next()
        }
    }
    
  beforeRouteEnter(to,from,next){
	next()
  }
  全局守卫: route.beforeEnter(to,from,next) main.js
  路由独享守卫: beforeEnter(to,from,next) 写在路由配置页route.js

8.Vuex

1.注册vuex

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters:{  //相当于vuex中的计算属性
        person(state,getters){
            return `${position}${userName}${getters.person} `
        }
    }
})

const state = {
  position: {},
  userName: ''
}
const mutations = {
  setPosition (state, val) {
    state.position = val
  },
  setUserName (state, val) {
    state.userName = val
  }
}
const actions = {
  setPosition ({
    commit
  }, val) {
    // 异步请求后端当前位置
    commit('setPosition', val)
  }
}


2. 使用vuex

使用store中的数据需要在计算属性中定义使用的变量。在data中定义不会双向绑定。

computed:{ name(){return this.$store.state.name} }

3.mapState /mapGetters

import {mapState,mapGetters} from 'vuex';
computed:{
...mapState(['name','age','look'])  //取值
    ...mapgetters({
         newPerson:person
    })
}


4. mutations/actions

export default new Vuex.Store({
    mutations:{
		change(state,{tempobj,name}){
            state.studentList.push(tempobj);
            state.name = name;
		}
	},
    actions:{
        changeStudent({commit},val){
            setTimeout(()=>{
                commit('change',val)
            },2000)
        }
    }
})

组件中使用mutations
methods:{
	handle(){
		this.$store.commit('change',{tempobj,name:fy}) //触发mutations中的同步任务用commit
        this.$store.dispatch('changeStudent',{tempobj,name:fy})//触发actions中的异步任务用dispatch
    }
}
也可以使用mapmutations/mapActions
import {mapMutations,mapActions} from 'vuex'
methods:{
		...mapMutations(['change']),  //mapmutations方法使用
         handle(){
		this.change('tempobj',name:'fy')
        } 
    
    	...mapActions(['changeStudent']),//mapActions方法使用
            this.changeStudent('tempobj',name:'fy')
	}

5.modules

根据功能vuex模块化

state会分模块,getters,mutations,actions会放在全局。

获取statae: this.$store.state.moduleName.xxx

获取getters: this.$store.getters.xxx

获取mutations: this.$store.commit('')

获取actions: this.$store.dispatch('')

namespaced:'true'//命名空间

有命名空间时,使用mapState,mapmutations,mapactions,mapgetters时需在前面加上模块前缀。

...mapXXX(['moduleName',['XXX','XXX']),

9.webpack配置

module.expots = {
	productionSourceMap:false, //是否打包sourceMap
	outputDir:'./dist'  //输出目录
	publicPath: process.env.NODE_ENV ? 'http://www.xxx.com' : '/',
	assetsDir:'assets', //静态资源打包进一个文件
	chainWebpack:config=>{
        config.resolve.alias.set('v',path.resolve(_dirname,'src/view'))
	}
}