Vue学习笔记

数据绑定:

单向绑定(v-bind):数据只能从data流向页面

双向绑定(v-model):数据不仅能从data流向页面,也能从页面流向data

 

el的两种写法:

new Vue时配置el属性

先创建vue实例,随后再通过vm.$mount('#root')指定el的值

 

data的两种写法:

对象式

函数式——学习到组件时,必须使用函数式

 

按键:

大多数的按键都可以配合keyup使用,除了ctrl、alt、shift、meta需要用keydown

 

时间修饰符:

prevent:阻止默认事件(常用)

stop:阻止冒泡

once:事件只触发一次

capture:使用事件的捕获模式

self:只有event.target是当前的操作元素时才触发

 

@click.stop
 

计算属性:

定义:要用的属性不存在,要通过已有属性计算

原理:底层借住Object.defineproperty提供的get和set函数实现

get函数:初次读取时会调用一次;当依赖发生变化时会再次调用

优势:与methods相比,内部有缓存机制

 

监视属性:

当被监视的属性变化时,回调函数自动调用

监视的两种写法:通过new Vue时的watch配置;通过vm.$watch监视

深度监测:vue中的watch默认不监测对象内部值的变化,配置deep:true可以监测对象内部值变化

 

监视的写法如下:

//完整写法
......
watch: {
  isHot:  {
    immediate:true,//初始化时让handler调用一下
  deep:true, handler(newValue, oldValue) { console.log('isHot被修改了', newValue, oldValue) } } } //简写,只执行handler watch:{ isHot(newValue, oldValue){ console.log('isHot被修改了', newValue, oldValue } }

//正常写法
vm.$watch('isHot', {
  immediate:true
  ......
}

//正常缩写
vm.$watch('isHot', function(newValue, oldValue){
  console.log('isHot'被修改了,newValue, oldValue, this)
}

  

computed和watch之间的区别:

computed能完成的功能,watch都可以完成

watch能完成的功能,computed不一定能完成,例如watch可以进行异步操作

被Vue管理的函数,最好写成普通函数;不给Vue管理的函数,最好写成箭头函数

 

绑定样式:

class样式写法:

  class=“xx"     xx可以是字符串、对象、数组

  字符串写法用于:   类名不确定,要动态获取

  对象写法用于:  要绑定多个样式,个数不确定,名字也不确定

  数组写法用于:  要绑定多个样式,个数确定,名字确定,但不确定用不用

 

style样式:

  :style="{fontSize: xxx}"其中xxx是动态值

  :style="{a, b}" 其中a,b是样式对象

 

条件渲染:

v-if:适用于频率较低场景;不展示的DOM直接被移除;v-if和v-else-if和v-else之间不能被打断

v-show:适用于频率较高的场景;不展示的DOM元素未被移除,仅仅使用样式隐藏

<template v-if="type === '0'">
    <el-button 
        size="small"
    >AAA</el-button>
    <el-button 
        size="small"
    >SQL拉取-Doris
    </el-button>
 </template>        

 

数据监测:

对象中数据通过setter实现监视,且要在new Vue时传入要监测的数据

(1):对象中后追加的属性,Vue默认不做响应式处理,如vm.object.xxx = "xxx"

(2):如需给后添加属性做响应式,需要使用以下API:

    Vue.set(target, propertyName/index, value)或 vm.$set(target, propertyName/index, value)

 

数组中数据通过包裹数组更新元素的方法实现

(1):调用原生对应的方法对数组进行更新

(2):重新解析模板,进而更新页面

 

修改数组中的某个元素需要使用以下API:

(1):push()、pop()、shift()、unshift()、splice()、sort()、reverse()

(2):Vue.set()、vm.$set()此两方法不能给vm或vm._data数据对象添加属性

 

收集表单数据:

<input type="text"/>,则v-model收集的是value值,用户输入的就是value值

<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值

<input type="checkbox"/>

1:没有配置input的value属性,那么收集的就是checked(是否勾选,为布尔值)

2:配置input的value属性:

  (1):v-model初始值是非数组,那么收集的就是checked(是否勾选,为布尔值)

  (2):v-model初始值是数组,那么收集的就是value组成的数组

 

Vue其它指令:

v-text:向其所在节点渲染文本内容,{{x}}不会

v-html:向指定节点渲染包含html结构内容,会替换所有内容,{{x}}不会,有安全性问题

v-cloak:本质是特殊属性,Vue实例创建完毕后会被删除;配合css可以解决网速慢显示出{{xx}}问题

v-once:所在节点在初次动态渲染后,转为静态内容,可用于优化性能

v-pre:跳过节点编译过程;不使用指令语法、键值语法的节点,会加快编译

 

Vue生命周期:

refs:

1:被用来给元素或子组件注册引用信息(id的替代者)

2:应用在html标签上获取的是真实DOM元素, 应用在组件标签上是组件实例对象(vc)

3:使用方式:

  打标识: <h1 ref="xxx"> ......</h1> 或 <School ref="xxx"></School>

  获取:this.$refs.xxx

 

props:

1:传递数据:<Demo name="xxx" />

2:接收数据:

  第一种方式(只接收):

    props:['name']

  第二种方式(限制类型):

    props: {

      name:Number

    }

  第三种方式(限制类型、限制必要性、指定默认值):

    props:{

      name:{

        type:String, //类型

        required:true, //必要性

        default: '老王' //默认值

      }

    }

3:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制内容到data中一份,然后去修改data中数值

 

props类型:

 

mixin(混入):

功能:可以把多个组件公用的配置提取成一个混入对象

使用方式:

  第一步定义混合,例如:

    {

      data(){....},

      methods:{....}

    }

  第二步使用混入,例如

    1:全局混入:Vue.mixin(xxx)

    2:局部混入: mixins:['xxx']

 

插件:

功能:用于增强Vue

本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后参数是插件使用者传递的数据

定义插件:

  对象:install = function (Vue, options) {

     Vue.filter(....)              // 1.添加全局过滤器

     Vue.directive(....)            // 2.添加全局指令

     Vue.mixin(....)              // 3.配置全局混入(合)

     Vue.prototype.$myMethod = function() {...}

     Vue.prototype.$myProperty = xxxx

     }

使用插件:Vue.use()

 

scoped样式:

作用:让样式在局部生效,防止冲突

写法:<style scoped>

 

WebStorage:

1:存储内容大小一般支持5MB左右(不同浏览器可能不同)

2:浏览器通过window.sessionStorage 和 window.localStorage属性来实现本地存储机制

3:相关API:

xxxxStorage.setItem('key', 'value') // 该方法接受一个键和值做参数,会将键值对添加进存储中,如键名存在,则更新其对应的值

xxxxStorage.getItem('key') //该方法接受一个键名作参数,返回键名对应的值

xxxxStorage.removeItem('key') //该方法接受一个键名作参数,并把该键名从存储中删除

xxxxStorage.clear() // 该方法会清空存储中的所有数据

4:

(1)SessionStorage中存储的内容会随着浏览器关闭而消失

(2) LocalStorage存储的内容,需要手动清除才会消失

(3) xxxxStorage.getItem(xxx)如果取不到对应的值,则返回值是null

(4)JSON.parse(null)结果依然是null

 

Vue与VueComponent的关系:

 

vue脚手架配置代理:

方法一:vue.config.js中添加如下配置

devServer: {
  proxy: "http://localhost:5000"  
}

(1)优点:配置简单,请求资源时直接发给前端(8080)即可

(2)缺点:不能配置多个代理,不能灵活的控制请求是否走代理

(3)工作方式:若按照上述配置代理,当请求了前端不存在的资源时,该请求会转发给服务器

 

方法二:编写vue.config.js配置具体代理规则:

module.exports = {
  devServer: {
        proxy: {
            '/api1': {
               target: 'http://localhost:5000', // 代理目标的基础路径
               changeOrigin: true,
               pathRewrite: {'^/api1': ''}
            },
             '/api2': {
               target: 'http://localhost:5000', // 代理目标的基础路径
               changeOrigin: true,
               pathRewrite: {'^/api1': ''}
            },
        }
  }    
}    

// changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
// changeOrigin设置为false时,服务器收到的请求头中的host为: localhost:8000
// changeOrigin默认为true

(1)优点:可以配置多个代理,且可以灵活的控制请求是否走代理

(2)缺点:配置略微你繁琐,请求资源时必须加前缀,如 http://localhost:8080/api1/students

 

组件自定义事件->子传父(3种方式)

//第一种
<template>
    <School :getSchoolName = "getSchoolName"></School>
</template>

methods:{
    getSchoolName(value){
      console.log('我收到了数据:', value)
    },
}

//在子组件中触发
props:['getSchoolName'],
    methods:{
        sendSchoolName(){
           this.getSchoolName(this.name)
        }
    }

//第二种
<template>
<Student @demo="m1"></Student>
</template>

methods:{
      m1(){
      console.log('demo被触发了')
    }
}

//在子组件中触发,之后需要执行this.$off
methods:{
    sendStudentName(){
        this.$emit('demo')
    },
    unbind(){
        //this.$off('atguigu')
        //this.$off(['atguigu', 'demo'])
        this.$off()
    },
    death(){
        this.$destroy()
    }
}


//第三种
<template>
<Student  @atguigu="getStudentName" ref="student"></Student>
</template>

methods:{
    getSchoolName(value){
      console.log('我收到了数据:', value)
    },
    getStudentName(value, ...params){
      console.log('我收到了数据', value, params)
    },
}

mounted(){
    this.$refs.student.$on('atguigu', this.getStudentName)
}

//在子组件中触发,之后需要执行this.$off
methods:{
    sendStudentName(){
        this.$emit('atguigu', this.name, 2224, 332, 322)
    },
    unbind(){
        //this.$off('atguigu')
        //this.$off(['atguigu', 'demo'])
        this.$off()
    },
    death(){
        this.$destroy()
    }
}
View Code

 

组件上也可以绑定原生DOM事件,需要使用native修饰符

 

全局事件总线(适用于任意组件间通信):

1:安装全局事件总线

new Vue({
  render: h => h(App),
  beforeCreate(){
    Vue.prototype.$bus = this
  }
}).$mount('#app')

2:使用事件总线

//接收数据
methods:{
    checkTodo(id){
      this.todos.forEach((todo) => {
        if (todo.id === id) todo.done = !todo.done
      })
    },
}
mounted(){
    this.$bus.$on('checkTodo', this.checkTodo)

  },
  beforeDestroy(){
    this.$bus.$off('checkTodo')
  }


//发送数据
methods: {
    //勾选or取消勾选
    handleCheck(id){
    //通知App组件将对应的todo对象的done值取反
    // this.checkTodo(id)
    this.$bus.$emit('checkTodo',id)
},

 

插槽

// 1:默认插槽,父组件
<HelloWorld title="美食" :listData="foods">
  <img src="./test.jpg" alt="">
</HelloWorld>

// 子组件HelloWorld,<slot>标签会对应显示<img>内容
<template>
  <div class="category">
    <h3>{{title}}分类</h3>
    <slot></slot>
  </div>
</template>


// 2:具名插槽,父组件
<div id="app">
    <HelloWorld title="美食" :listData="foods">
      <img slot="center" src="./test.jpg" alt="">
      <div slot="footer">更多美食</div>
    </HelloWorld>

    <HelloWorld title="游戏">
      <ul slot="center">
        <li v-for="(g, index) in games" :key="index">{{games}}</li>
      </ul>

      <template v-slot:footer>
        <div class="foot" >
          <div>网络游戏</div>
          <div>单机游戏</div>
        </div>
        <h4>hahaha</h4>
      </template>
    </HelloWorld>
</div>

// 子组件HelloWorld
  <div class="category">
    <h3>{{title}}分类</h3>
    <slot name="center"></slot>
    <slot name="footer"></slot>
  </div>


// 3.作用域插槽,父组件,以下两个template等同
<HelloWorld title="美食">
      <template scope="{foods}">
        <ul>
          <li v-for="(g, index) in foods" :key="index">
            {{g}}
          </li>
        </ul>
      </template>

      <template slot-scope="atguigu">
        <ul>
          <li v-for="(g, index) in atguigu.foods" :key="index">
            {{g}}
          </li>
        </ul>
      </template>
 </HelloWorld>

//子组件HelloWorld
<template>
  <div class="category">
    <h3>{{title}}分类</h3>
    <slot :foods="foods"></slot>
  </div>
</template>

export default {
  name: 'HelloWorld',
  data() {
    return {
      foods:['火锅','烧烤', '小龙虾'],
    }
  },
}
View Code

 

Vuex:

 

Vue3项目结构

关于main.js文件

 

setup

 

setup注意点

 

ref函数

 

reactive函数

 

 

vue3的响应式

实现原理:

  通过Proxy(拦截):拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、删除等

  通过Reflect(反射):对源对象的属性进行操作

 

reactive对比ref

 

vue3——computed

 

vue3——watch,监视ref

 

 监视reactive

 

watchEffect

 

vue3生命周期

与vue的差距大体只在最后部分

 

hook函数

 

shallowReactive与shallowRef

 

readonly与shallowReadonly

 

toRaw与markRaw

 

customRef

 

响应式数据的判断

 

新的组件

Fragment

 

Teleport

 

Suspense

 

posted @ 2021-10-31 07:50  天叔  阅读(189)  评论(0编辑  收藏  举报