vue知识概览(基础知识巩固)

vue.js

用于构建用户界面的渐进式框架,双向数据绑定
双向数据绑定原理:通过数据劫持和发布-订阅模式实现,数据劫持通过Object.defineProperty()实现,
劫持属性的setter与getter,数据属性发生变动,发布消息给订阅,触发对应的监听回调
const app = new Vue({
  el:'#app',
  data:{ msg:'小猪皮' }
});

MVVM

model:模型,数据对象(data)
view:视图界面
viewModel:视图模型(vue的实例)
视图通过数据绑定读取model数据对象,
model数据对象通过DOM监听获取DOM内容

模板语法(动态的html)

1.双大括号表达式:{{kn}}
2.强制数据绑定:v-bind:src="kn"/:src="kn"
3.绑定事件监听:v-on:event="mn"/@event="mn"
<!-- kn:keyName mn:methodsName -->

计算属性computed/监视watch

<input type="text" v-model="computedValue">
<input type="text" v-model="comVal">
<script>
const vm = new Vue({
  el:"#app",
  data:{firstName:'luo', lastName:'xianze'},
  computed:{// 计算属性存在缓存,多次读取只执行一次get
    computedValue(){// 初始化显示/相关数据改变
      return this.firstName + this.lastName;
    },
    comVal:{
      get(){// 读取属性值,根据相关数据返回属性值
        return this.firstName + '-' this.lastName;
      },
      set(val){// 当前属性发生改变,todo
        const names = val.split('-');
        this.firstName = names[0];
        this.lastName = names[1];
      }
    }
  },
  watch:{// 监听firstName的改变,初始化不执行该函数
    firstName:function(value){
      this.computedValue = value + this.lastName;
    },
    todos:{
      deep:true, // 深度监视
      immediate:true,// 页面渲染完成,也会执行
      handler:function(value){
        // todo something
      }
    }
  }
})
// 监听,keyName支持.模式,data.a.b
vm.$watch('keyName',function(value){})
</script>

class绑定/style绑定

:class="xxx" xxx字符串->data中data[xxx]
:class="{xClass:true/false,yClass:isY}" 对象
  true,新增类,false,元素不新增该类;isY为data[isY]
:class='getClassName()' 函数
  methods:{
    getClassName:function(){
      return {active:this.isActive}
    }
  }
:class="['active', 'line']" 数组字符串
  className = 'active line'
:class="[active,line]" 数组变量
  根据data中的active与line
:style="{color:dc, fontSize: dfs + 'px'}" 变量
  dc、dfs为data中的属性值

v-if、v-else-if、v-else

使用示例:
<span v-if='变量值/表达式'></span>
<span v-else-if='变量值/表达式'></span>
<span v-else></span>
<div class="form-control" v-if='isHowName'>
  <label for="userName">用户账号</label>
  <input type="text" name="userName" id="userName">
</div>
<div class="form-control" v-else>
  <label for="userEmail">用户邮箱</label>
  <input type="text" name="userEmail" id="userEmail">
</div>
<!-- form-control切换时,input的输入内容不变,vue进行dom
渲染,出于性能的考虑,尽量复用已存在的元素,
若希望重新渲染dom,需要给元素新增不同的key -->

v-show

v-show 与 v-if的区别,v-show:false将DOM元素设置display:none;
v-if:false将DOM元素删除
显示与隐藏切换频繁建议使用v-show

v-for

建议使用v-for时,内容元素新增key,可更高效地更新虚拟DOM
数组触发响应式的方法:
push,pop,shift,unshift,splice,sort,reverse
不触发:arr[1] = 'xzp';
<!-- 遍历数组 -->
<li v-for="(item, index) in arr" :key="item.id">
  {{index}}-{{item}}
</li>
<!-- 遍历对象 -->
<li v-for="(value, key, index) in obj" :key="key">
  {{key}}-{{value}}
</li>

事件监听v-on

示例1:<button @click='add'>点击</button>
示例2:<button @click='add()'>点击</button>
示例3:<button @click='add(2)'>点击</button>
示例4:<button @click='add(2, $event)'>点击</button>
示例5:<button @click='add(name, $event)'>点击</button>
add:function(num){
  console.log(num);
  // 示例1:event对象,示例2:undefined,示例3:2
  // 示例4:2,event对象,示例5:xzp,event对象
}

事件修饰符

<div>
  <!-- stop阻止冒泡事件 -->
  <button @click.stop='add'></button>
  <!-- prevent阻止默认事件 -->
  <button @contextmenu.prevent='add'></button>
  <!-- 按键修饰符 keyCode 按键的keyCode:enter、space -->
  <input @keyup.keyCode="xzpKeyUp">
  <input @keyup.enter="xzpKeyUp">
  <!-- 按键修饰符.once事件生效单次 -->
  <input @click.once="xzpOnce">
</div>
<script>
new Vue({
  methods:{
    xzpKeyUp(event){
      console.log(event.keyCode)
    }
  }
})
</script>

v-model数据双向绑定

v-model由 v-bind 与 v-on组合实现<input :value="name" @input="changeName">
<form @submit.prevent="handleSubmit">
  <input type = 'text' v-model='name'>
  <!-- 单选框 -->
  <input type="radio" id="male" value="male" v-model='sex'>
  <label for="male"></label>
  <input type="radio" id="female" value="female" v-model='sex'>
  <label for="female"></label>
  <!-- 复选框 like为数组 -->
  <input type="checkbox" id="yyy" value='yyy' v-model='like'>
  <label for="yyy">yyy</label>
  <input type="checkbox" id="jsx" value='jsx' v-model='like'>
  <label for="jsx">jsx</label>
  <label v-for="(item, index) in likeArr" :for="index+item">
    <input type="checkbox" id="index+item" :value="item" v-model='like'>{{item}}
  </label>
  <!-- 下拉框 -->
  <select v-model='fruit'>
    <option v-for="(item, index) in fruitArr"
    :key="item.value" :value="item.value">{{item.name}}</option>
  </select>
</form>
new Vue({ el:'#app',
  data:{ 
    name:'xzp',sex:'male', like:'jsx',
    likeArr:['yyy','jsx'], fruit:'',
    fruitArr:[
      {name:'无',value:''},
      {name:'橙子',value:'o'},
      {name:'西瓜',value:'w'},
      {name:'苹果',value:'a'}
    ]
  },
  methods:{
    handleSubmit(){console.log(this);}
  }
});

双向绑定的修饰符

<!-- 1.lazy,失去焦点或回车,数据更新 -->
<input type='text' v-model.lazy='city'>
<!-- 2.number,数字类型将输入框结果改为number -->
<input type='number' v-model.number='age'>
<!-- 3.trim,去掉输入框头尾空格 -->
<input type='text' v-model.trim='email'>

vue的生命周期

new Vue({ el:'#app',
  data:{},
  beforeCreate(){ /* 创建实例对象之前 */ },
  created(){ /* 创建实例对象 */ },
  beforeMount(){ /* 初始化渲染之前 */ },
  mounted(){ /* 初始化渲染完成 */ },
  beforeUpdate(){ /* 更新之前  */ },
  updated(){ /* 更新完成 */ },
  beforeDestroy(){ /* 销毁之前 */ },
  destroyed(){ /* 销毁 */ }
  methods:{
    destroyVM(){
      this.$destroy();// 销毁
    }
  }
});

在这里插入图片描述

v-once

单次渲染,data.message改变时,页面将不变
<span v-once>{{message}}</span>

v-html

将数据解析为html,data.url = '<a href="www.baidu.com"></a>
<span v-html='url'></span>

v-text (不经常使用)

使用v-text 会覆盖标签原有的内容
<span v-text='text'></span>

v-pre (不解析内容)

<span v-pre>{{name}}</span>
界面显示:{{name}}

v-cloak

<div id='app' v-cloak></div>
vue解析之前,div存在属性v-cloak
vue解析之后,div属性v-cloak消失
样式写入[v-cloak]{ display:none; }
防止闪屏(不常用)

ref

<input ref='keyName' value='xxx'>
<script>
  // input对象
  this.$refs.keyName;
</script>

过渡/动画

<transition name = 'xxx'>
  <div v-show='isShow'>示例显示隐藏</div>
</transition>
/* 显示隐藏 过渡效果 xxx 为transition的name */
.xxx-enter-active,.xxx-leave-active{
  transition: opacity 1s;
}
.xxx-enter, .xxx-leave-to{ opacity: 0; }
<transition name = 'move'>
  <div v-show='isShow'>示例移动</div>
</transition>
/* 显示 过渡效果 */
.move-enter-active{ transition:all 1s; }
/* 隐藏 过渡效果 */
.move-leave-active{ transition: all 2s; }
.move-enter, .move-leave-to{
  opacity: 0;
  transform:translateX(20px);
  /* >0px向右移出隐藏,<0px向左移出隐藏 */
}

过滤器

/* 全局 */
Vue.filter('filterName', function(value, format){// todo
  return filterValue;
});
/* 局部 */
filters{'filterName':function(value, format){// todo
  return filterValue;
}};
<div>{{data | filterName(format)}}</div>

指令新增directive

/* 全局 */
Vue.directive('directive-name', function(el, binding){
  // el 指令所在的标签对象,binding指令相关信息数据对象
})
/* 局部 */
directives:{
  'directive-name'(el, binding){
    // el 指令所在的标签对象,binding指令相关信息数据对象
  }
}
/* 使用指令 */
v-directive-name

插件plugin

(function(){
  const MyPlugin = {};
  MyPlugin.install = function(Vue, options){
    Vue.globalFunction = function(){
      // 添加全局方法
    }
    Vue.directive('directive-name', function(el, binding){
      // 添加全局资源(指令)
    })
    Vue.prototype.$myMethod = function(){
      // 添加实例方法
    }
  }
  window.MyPlugin = MyPlugin; // 向外暴露
})()
// 声明使用插件
Vue.use(MyPlugin);
Vue.globalFunction();
vm.$myMethod();

组件实例

<template>
  <div>组件示例:App</div>
</template>
<script>
export default {
  data(){// 组件data必须为函数
    return {};
  }
}
</script>
<style lang="less"></style>
import Vue from 'vue'
import App from './App.vue'
new Vue({
  el:'#app',
  components:{
    App
  },
  template:`<App />
})

组件通信(父组件->子组件/子组件->父组件)

<template>
  <div @click="deleteItem">{{itemprops}}</div>
</template>
<script>
export default {
  // props:['itemprops']数组类型(新版本中不可用)
  props:{
    // 限制props的类型
    itempropstype:Array|String|Number|Object|Function,
    itemsex:{
      type:String,
    // 设置默认值,若默认值为对象/数组,default为函数
      default:'male', // default(){return []/{}}
      required:true // 必须传值
      validator(value){ return true/false;} //验证规则
    }
  },
  methods:{
    deleteItem(){
      let {deleteF} = this;
      deleteF();
      // 触发自定义事件
      this.$emit('deleteLove', value);
    }
  }
}
</script>
<style lang="less"></style>
<!-- 父组件 -->
<template>
  <div>
    父组件传递props
    <item :propstype="type" :itemsex="sex"
    :deleteF="deleteF" @deleteLove="deleteL" />
  </div>
</template>
<script>
export default {
  data:{ type:'String',sex:'male' }
  methods:{ 
    deleteF(){}, // todo
    deleteL(){} // todo
  }
}
</script>

PubSub

安装npm install --save pubsub-js
// 引入
import PubSub from 'pubsub-js'
// 消息监听
PubSub.subscribe('titleName',function(msg, data){
  // todo
});
PubSub.publish('titleName',data)

子组件访问父组件

this.$parent 访问父组件
this.$root 访问根组件

插槽slot

<!-- 父组件插入元素 -->
<cpn slot><button>我是插槽按钮</button></cpn>
<!-- 子组件cpn插槽 -->
<div>
  <span>我是子组件</span>
  <slot><button>我是插槽默认值</button></slot>
</div>

具名插槽

<!-- 子组件需要多个插槽 -->
<div>
  <slot name='left'></slot>
  <slot name='center'></slot>
  <slot name='right'></slot>
</div>
<!-- 父组件需要传入名称 -->
<cpn>
  <span slot='center'>center插槽内容</span>
  <span slot='right'>right插槽内容</span>
</cpn>

插槽作用域

父组件替换插槽的数据,由子组件提供
<!-- 父组件 -->
<cpn>
  <template slot-scope="slot">
    <!-- 获取子组件绑定数据slot.data -->
    <span v-for="item in slot.data">{{item}}</span>
  </template>
</cpn>
<!-- 子组件插槽 -->
<slot :data="nameArr"></slot>
<!-- 
  data(){
    return { nameArr:['yyy','jsx','hh'] }
  }
 -->

vue cli脚手架

安装脚手架:npm install -g vue-cli

vue 路由的使用

npm install--> vue-router
新增路径文件夹router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
Vue.use(VueRouter);
export default new VueRouter({
  routes:[
    { path:'/about', component:About },
    { path:'/home', component:Home },
    { path:'/', redirect:'/home'} //默认路径
  ]
})
/* 根组件引入router */
import router from './router'
new Vue({
  router
})
/* 入口页面引用 */
<div class="list-link">
  <router-link to="/about">about</router-link>
  <router-link to="/home">home</router-link>
</div>
<div class="div-view"><!-- 显示内容 -->
  <router-view></router-view>
</div>

vue嵌套路由

export default new VueRouter({
  routes:[
    { path:'/about', component:About },
    { path:'/home', component:Home,
      children:[
        {
          path:'/home/new',
          component:New
        },
        {
          path:'message',
          component:Message
        },
        { path:'', redirect:'/home/new'}
      ]
    },
    { path:'/', redirect:'/home'} //默认路径
  ]
})
<!-- Home组件 -->
<router-link to="/home/new">new</router-link>
<router-link to="/home/message">message</router-link>

缓存路由组件

切换路由组件,原有的数据将被初始化
需要使用标签keep-alive
<div id="app" class='wrapper'>
    <keep-alive>
        <!-- 需要缓存的视图组件 --> 
        <router-view v-if="$route.meta.keepAlive"></router-view>
     </keep-alive>
      <!-- 不需要缓存的视图组件 -->
     <router-view v-if="!$route.meta.keepAlive"></router-view>
</div>

路由组件传递数据

// params参数
{
  path:"/home/message/detail/:id",// 声明接收
  component:Detail
}
// query参数路径不需要声明
<!-- 父页面 params -->
<router-link :to="`/home/message/detail/${msg.id}`">{{msg.title}}</router-link>
<!-- 父页面 query -->
<router-link :to="`/home/message/detail/?id=${msg.id}`">{{msg.title}}</router-link>
<!-- 子页面接收数据 params -->
<span>{{$route.params.id}}</span>
<!-- 子页面接收数据 query -->
<span>{{$route.query.id}}</span>
<script>
export default {
  mounted(){
    const id = this.$route.params.id;
  },
  watch:{
    $route:function(value){
      const id = value.param.id;
    }
  }
}
</script>
<!-- props传递 -->
<router-view :id='id'></router-view>
<!-- 子页面接收 -->
<script>
export default {
  props:{
    id:{
      type:Number,
      required:true
    }
  }
}
</script>

vuex

对vue应用中多个组件的共享状态进行集中式管理
状态自管理应用(单向数据流)
  state:驱动应用的数据源
  view:已声明方式将state映射到视图
  actions:响应在view上的用户输入导致状态变化
多组件共享状态
  1.多个视图依赖相同的状态
  2.不同视图行为需要变更同一状态

在这里插入图片描述

/* vuex的核心管理对象模块:store */
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {// 初始化状态
  count:0
} 
const mutations = {
  ADD(state, val){
    state.count += val
  },
  SUB(state, val){
    state.count -= val
  }
}
const actions = {
  add({commit}, val){// 提交mutation
    commit('ADD',val)
  },
  sub({commit}, val){// 提交mutation
    commit('SUB',val)
  },
  oddAdd({commit, state}, val){
    if(state.count%2===1){
      commit('ADD',val)
    }
  }
}
const getters = {
  evenOrOdd(state){ // 读取属性
    return state.count%2 ===0 ? '偶数' : '奇数';
  }
}
import otherVuex from './otherVuex.stroe'
const modules = {
  {
    //单个模块的vuex
    otherVuex.state, otherVuex.getters, otherVuex.mutations, otherVuex.actions
  }
}
export default new Vuex.Store({
  state, // 状态对象
  mutations, // 包含多个更新state函数的对象(同步)
  actions, // 包含多个对应事件回调函数的对象
  getters // 包含多个getter计算属性函数的对象
})
/* ------------------------------ */
/* 在入口文件配置store */
import store from './store'
new Vue({
  store
}).$mount('#app')
/* ------------------------------ */
/* 组件获取state */
this.$store.state[keyName];
/* template <span>{{$store.state[keyName]}}</span> */
export default{
  computed:{
    evenOrOdd(){  // 获取getters
      return this.$store.getters.evenOrOdd
    }
  },
  methods:{
    add(val){ // 通知vuex修改state
      this.$store.dispatch('add', val)
    },
    sub(val){
      this.$stor.dispatch('sub',val)
    }
  }
}
/* vuex语法糖 */
import { mapState, mapGetters, mapActions } from 'vuex'
export default{
  computed:{
    ...mapState(['count']), // 直接使用<span>count</span>
    ...mapGetters(['evenOrOdd'])// 直接使用evenOrOdd
    // ...mapGetters({evenOrOdd:'eoo'})// 名称不一致,使用eoo
  },
  methods:{
    ...mapActions(['add','sub','oddAdd']) // 名称需要一致
  }
}
总结:vuex通过全局注入store对象实现组件间状态共享;
组件通过dispatch分发action给store,store调用对应事件的回调函数;
回调函数提交对mutations的请求,mutations对state进行修改;
state改变后直接分发或通过getter将数据给组件。

vue3

1.性能提升
2.新增特性 composition、setup、新组件、新API
安装命令 npm install -g @vue/cli
新建项目 vue create 项目名称

vue3与vue2

1.vue3模板template可以没有根标签
2.lang='ts'可以使用typescript
3.defineComponent函数,定义组件,传入组件对象

vue3-setup、ref、reactive

1.setup-函数,执行一次
  返回对象,对象中属性可在模板中直接使用
2.ref-定义响应式数据(基本类型:number,boolean,sting,undefined,null) 
  const num = ref(0),num为对象
3.reactive-定义响应式数据(复杂数据,对象,数组) 
  const obj = reactive({}),proxy代理对象(深层次)
<template>
  <!-- 直接使用,不需要.value -->
  <span>{{count}}</span>
  <button @click="add">+1</button>
  <button @click="updateAge">birthday</button>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from 'vue';
export default defineComponent({
  name: 'App',
  setup(){
    console.log('执行一次')
    const count = ref(0)
    const obj = {
      name:'xzp',
      age:18,
      fruit:['apple']
    }
    const user = reactive(obj)
    function add(){
      count.value ++
    }
    const updateAge = ()=>{
      // 代理user可删除,修改,新增属性
      // 修改obj,对象会改变,界面渲染不更新
      user.age +=1
      user.fruit.push('org')
      user.love = 'yyy'
    }
    return { count, add, updateAge }
  }
});
</script>

setup细节问题

1.setup于beforeCreate回调之前执行,且执行单次
2.不可以在setup中使用this
3.composition API相关回调不可用
4.setup返回值为对象,内部属性与方法,模板可用对象属性
5.setup对象、data对象、methods对象合并,模板中可用对象属性
6.vue3中尽量不要混合使用data,methods,setup(重名,setup优先)
7.methods可访问setup提供的属性与方法,setup不可访问data与methods
8.setup不可以异步

setup参数

setup(props, context){
  // props,对象:父级传递子组件的数据,
  // 子组件使用props接收的数据
  // context,对象:attrs对象(获取子组件未声明属性)
  // emit方法(分发事件),slots对象(插槽)
  context.emit('xxx', str:string); //xxx父级setup返回的函数
}

ref/reactive细节问题

1.ref传入对象,需要经过reactive处理,形参proxy类型的对象
2.ref在js中需要.value获取内容,模板中不需要(模板解析自动添加.value)

属性计算computed和监视watch

import {computed, watch, watchEffect} from 'vue'
setup(){
  const user = reactive({
    firstName:'x',
    lastName:'zp'
  })
  // vue3计算属性(只读)
  const fullName = computed(()=>{
    return user.firstName + '_' + user.lastName
  })
  // vue3计算属性(读写,反向修改user)
  const fullName2 = computed({
    get(){
      return user.firstName + user.lastName
    },
    set(val:string){
      let names = val.split('_')
      user.firstName = names[0]
      user.lastName = names[1]
    }
  })
  // 监视数据变化 val =>新的user
  watch(user, (val)=>{
    fullName3.value = val.firstName + '_' + val.lastName
  },{immediate:true, deep:true})
  // immediate默认执行一次,若不配置,需要组件user数据存在更新才会执行
  // deep深度监视
  return {
    user,
    fullName,
    fullName2,
    fullName3
  }
}

watchEffect 与 watch

1.watchEffect不需要配置immediate,默认执行
2.watch可以监视多个数据
3.watch监视非响应式数据需要
watch([()=>user.firstName, full3Name],()=>{
  // todo
})

vue3生命周期

beforeCreate -> setup
created -> setup
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
<template>
<div class="about">
  <h2>msg: {{msg}}</h2>
  <hr>
  <button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import {
  ref, onMounted, onUpdated,
  onUnmounted, onBeforeMount, 
  onBeforeUpdate, onBeforeUnmount
} from "vue"
export default {
  /* ----2.x---- */
  beforeCreate () {
    console.log('beforeCreate()')
  },
  created () {
    console.log('created')
  },
  beforeMount () {
    console.log('beforeMount')
  },
  mounted () {
    console.log('mounted')
  },
  beforeUpdate () {
    console.log('beforeUpdate')
  },
  updated () {
    console.log('updated')
  },
  /* 3.x中beforeDestroy */
  beforeUnmount () {
    console.log('beforeUnmount')
  },
  /* 3.x中destroyed */
  unmounted () {
     console.log('unmounted')
  },
  /* ----3.x---- */
  setup() {
    const msg = ref('abc')
    const update = () => {
      msg.value += '--'
    }
    onBeforeMount(() => {
      console.log('--onBeforeMount')
    })
    onMounted(() => {
      console.log('--onMounted')
    })
    onBeforeUpdate(() => {
      console.log('--onBeforeUpdate')
    })
    onUpdated(() => {
      console.log('--onUpdated')
    })
    onBeforeUnmount(() => {
      console.log('--onBeforeUnmount')
    })
    onUnmounted(() => {
      console.log('--onUnmounted')
    })
    return { msg, update}
  }
}
</script>
3.x的生命周期函数执行比2.x中的快

hook函数

新建文件夹hooks,文件命名useXXX.ts
/* 封装hooks,useMouseP */
import { ref, onMounted, onBeforeUnmount } from 'vue'
export default function(){
  const x = ref(0)
  const y = res(0)
  const clickEvent = (event:MouseEvent){
    x.value = event.pageX
    y.value = event.pageY
  }
  onMounted(()=>{
    window.addEventListener('click', clickEvent)
  })
  onBeforeUnmount(()=>{
    window.removeEventListener('click', clickEvent)
  })
  return {x,y}
}
/* 使用hooks */
import useMouseP from './hooks/useMouseP'
setup(){
  const {x,y} = useMouseP()
}

自定义hooks函数

封装request
import { ref } from 'vue'
import axios from 'axios'
export default function <T>(url: string) {
  const loading = ref(true)
  const data = ref<T | null>(null)
  const errorMsg = ref('')
  axios.get(url).then(response => {
    loading.value = false
    data.value = response.data
  }).catch(error => {
    loading.value = false
    errorMsg.value = error.message || '未知错误'
  })
  return {
    loading, data, errorMsg
  }
}
/* 调用 */
const { 
  loading,
  data, errorMsg } = useRequest<object>('/login')

toRefs

可以将响应式对象转换成普通对象,该普通对象的每个属性
都是单个的ref
setup(){
  const state = reactive({
    name:'xzp',
    age:25
  })
  const {name, age } = toRefs(state)
  function updateAge(){
    age.value ++
  }
  return {
    name, age
  }
}

ref获取元素

<template>
  <input type='text' ref='inputName'>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
export default defineComponent({
  name: 'app',
  setup(){
    const inputRef = ref<HTMLElement | null>(null)
    onMounted(()=>{
      inputRef.value && inputRef.value.focus() //自动获取焦点
    })
    return { inputRef }
  }
})
</script>
<style>
</style>

shallowReactive 与 shallowRef

1.shallowReactive 浅监控(data.a)
2.shallowRef 浅监控(处理value的响应式
不进行对象的reactive处理)

readonly 与 shallowReadonly

1.readonly 深度只读
2.shallowReadonly 浅只读(data.a.b深数据可以改)

toRaw 与 markRow

import {toRaw, markRow } from 'vue'
interface UserInfo {
  name:string;
  age:number;
  likes?:string[];
}
setup(){
  const state = reactive({
    name:"xzp",
    age:25
  })
  const testToRaw =()=>{
    const user = toRaw(state)
    user.age += 1
    // 将代理对象变成普通对象,数据改变,界面不刷新
  }
  const testMarkRaw = ()=>{
    const like = [ 'yyy', 'jsx' ]
    state.likes = markRaw(likes)
    // markRaw标记的对象数据,不可以成为代理对象
    // 修改state.likes 界面将不改变
  }
  return {
    state
  }
}

toRef特点与使用

setup()const state = reactive({
  age:25,
  money:25
})
// 响应式对象的属性变成ref对象
const age = toRef(state, 'age')
// 响应式对象的属性使用ref包装,成为ref对象
const money = ref(state.money)

自定义ref

自定义hook防抖函数
import { customRef } from 'vue'
function useDebouncedRef<T>(value:T, delay =200){
  let timeOutId:number
  return customRef((track, trigger)=>{
    return {
      get(){
        // 启用vue数据追踪
        track()
        return value
      },
      set(newValueT){
        clearTimeout(timeOutId)
        // 开启定时器
        setTimeout(()=>{
          value = newValue
          // 更新数据
          trigger()
        }, delay)
      }
    }
    
  })
}

provide 与 inject

组件通信(数据非响应式)
import { provide, inject } from 'vue'
/* 父组件声明提供数据 */
setup(){
  const name = ref('name')
  // 声明提供
  provide('name', name)
  return { name }
}
/* 子组件声明接收 */
setup(){
  const name = inject('name')
  return { name }
}

响应式数据判断

1.isRef 判断数据是否为ref对象
2.isReactive 判断数据是否为reactive创建的响应式代理
3.isReadonly 判断数据是否为readonly创建的只读代理
4.isProxy 判断数据是否为reactive或readonly方法创建的代理

vue2和vue3的区别

vue3支持大多数vue2的特性
vue3存在一套更强的组合API代替vue2中option IPI 复用性更强
更好的支持typescript
重写虚拟dom,性能更好
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值