Vue相关的细节

147 阅读5分钟

1.插槽

  • 具名插槽:
//接收name="h"
<template v-slot:h><p>sdfsdf</p></template>
<template #h><p>sdfsdf</p></template>
  • 作用域插槽
<template v-slot:default="strProps"><p>{{strProps.str.job}}</p></template>
//接收
<slot v-bind:str="strData"></slot>

插槽:v-slot:header 可以被重写为 #header:,插槽名明确后才能进行简写,否则不可以简写 动态插槽:

<template v-slot:[dynamicSlotName]>
    ...
  </template>

插槽:定义方法

<todo-list v-slot="{ item }">
  <i class="fas fa-check"></i>
  <span class="green">{{ item }}</span>
</todo-list>

插槽重名名

<todo-list v-slot="{ item: todo }">
  <i class="fas fa-check"></i>
  <span class="green">{{ todo }}</span>
</todo-list>

2.new Vue()实例方法

$data
$el
$watch
当一个 Vue 实例被创建时,它将 `data` 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。

3.vuex

方法:dispatch触发action->action commit触发mutations修改state

  • modules:可以划分模块
modules:{
  m1:{
    namespaced:true,  //开启命名空间
    state:{
      aa:'11'
    },
    getters:{},
    mutations:{
      bb(){

      }
    },
    actions:{}
  }
}

//使用
{{$store.state.m1.aa}}
this.$store.commit('m1/bb')
  • map系列方法
import {mapMutatons} from 'vuex'
methods:{
  ...mapMutations('m1',['loginMutation'])
<!-- 使用 -->
  add(){
    this.loginMutation()
  }
}
  1. vue的修饰符特别有用
v-once 一次更新不再更新

v-html html转换指令

动态指令:<a v-bind:[attributeName]="url"> ... </a>,
attributeName变化  指令变化,动态参数null值会移除绑定,其他非字符串会警告,
动态指令中空格和引号是无效的,指令名称的大写都会自动转换为小写

v-on:submit.prevent//调用 event.preventDefault():
//防抖
Vue 没有内置支持防抖和节流,但可以使用 [Lodash](https://lodash.com/) 等库来实现:
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
created() {
    // 用 Lodash 的防抖函数
    this.debouncedClick = _.debounce(this.click, 500)
  },
//计算属性存在get和set:
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
//动态样式
:class="[isActive ? activeClass : '', errorClass]"
:class="[{ active: isActive }, errorClass]"
:style="[baseStyles, overridingStyles]"
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>   //兼容性
//访问原始的Dom事件
@click="warn('Form cannot be submitted yet.', $event)"
//执行多个方法用逗号分隔
@click="one($event), two($event)"
<!-- 阻止单击事件继续传播 -->
<a @click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form @submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发   -->
<!-- 而不会等待 `onScroll` 完成                   -->
<!-- 这其中包含 `event.preventDefault()` 的情况   -->
<div @scroll.passive="onScroll">...</div>

.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

动态组件:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component :is="currentTabComponent"></component>

非字符串模板:为写在html中的组件不能使用驼峰的形式引入组件,需要用下划线的形式 字符串模板:template中引入可以使用驼峰 使用组件的时候定义的状态值和定义的方法,会直接作用于组件内部的根节点上 如果你希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false 通过将 inheritAttrs 选项设置为 false,你可以访问组件的 $attrs property,该 property 包括组件 propsemits property 中未包含的所有属性 (例如,classstylev-on 监听器等)。

app.component('date-picker', {
  inheritAttrs: false,
  template: `
    <div class="date-picker">
      <input type="datetime-local" v-bind="$attrs" />
    </div>
  `
})

provide inject:跨越多级子级传递数据

provide没发访问data中动态数据,需要使用return的返回形式:
provide() {
    return {
      todoLength: this.todos.length
    }
  },

provide是单项的数据传递,类似于props,并且provide不是响应式的,需要用计算属性实现响应式

provide() {
    return {
      todoLength: Vue.computed(() => this.todos.length)
    }
  }

异步组件:const { createApp, defineAsyncComponent } = Vue,defineAsyncComponent 异步加载组件;配合Suspense使用实现加载动画

transform硬件加速可以设定一些参数,任何一个即可

perspective: 1000px;
backface-visibility: hidden;
transform: translateZ(0);

动画class规则:如果你使用了 <transition name="my-transition">,那么 v-enter-from会替换为 my-transition-enter-from

:duration="{ enter: 500, leave: 800 }"  //过度效果

添加 :css="false",也会让 Vue 会跳过 CSS 的检测,除了性能略高之外,这可以避免过渡过程中 CSS 规则的影响。

需要注意的是使用 FLIP 过渡的元素不能设置为 display: inline。作为替代方案,可以设置为 display: inline-block 或者将元素放置于 flex 布局中。

setUP组件中无法获取到this;setup中定义的方法都是非响应式的,需要用到ref进行操作

// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
// 在我们的组件内
setup (props) {
  let repositories = []
   // 使用 `toRefs` 创建对prop的 `user` property 的响应式引用
  const { user } = toRefs(props)
  const getUserRepositories = async () => {
    repositories = await fetchUserRepositories(props.user)
  }
   onMounted(getUserRepositories)

  // 在 user prop 的响应式引用上设置一个侦听器
  watch(user, getUserRepositories)
  return {
    repositories,
    getUserRepositories // 返回的函数与方法的行为相同
  }
}

watch监听user变化执行后面的方法

setup可以进行组合式的api拆分,传递两个参数context,props

setup中props是响应式的,无法解构,所以需要toRefs取进行解析,const { title } = toRefs(props),如果title是非出现的则使用const title = toRef(props, 'title')

context是非响应式的,所以可以直接解构

export default {
  setup(props, { attrs, slots, emit }) {
    ...
  }
}

attrsslots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.xslots.x 的方式引用 property。请注意,与 props 不同,attrsslots响应式的。如果你打算根据 attrsslots 更改应用副作用,那么应该在 onUpdated生命周期钩子中执行此操作。

执行 setup 时,组件实例尚未被创建。因此,你只能访问以下 property:

  • props
  • attrs
  • slots
  • emit

换句话说,你将无法访问以下组件选项:

  • data
  • computed
  • methods

setup中除了beforecreate created,和选项式api都有对应的钩子,只是前面添加了on,例如onMounted

因为 setup 是围绕 beforeCreatecreated 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写

setup中使用provide inject,

1.都需要从vue实例中引入

2.为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 refreactive

3.为了防止inject修改值,可以使用只读写法 provide('location', readonly(location))

ref和reactive的区别:

ref是定义一些基本的数据类型,reactive定义一些复杂的数据类型

reactive需要借助torefs来进行响应式的转换

setup中watchEffect

 watchEffect(() => {
        // 这个副作用在 DOM 更新之前运行,因此,模板引用还没有持有对元素的引用。
        console.log(root.value) // => null
      })
watchEffect(() => {
        console.log(root.value) // => <div>This is a root element</div>
      }, 
      {
        flush: 'post'
      })

使用flush:‘post’来进行监听才可以获取真实的dom,

flush 选项还接受 sync,这将强制效果始终同步触发。然而,这是低效的,应该很少需要。

mixin和组件数据冲突,以mixin的数据优先,mixin的钩子会在组件钩子之前运行,并且合并,其他的有冲突以组件的为主

注册自定义组件:directive

<div id="dynamicexample">
  <h3>Scroll down inside this section ↓</h3>
  <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
const app = Vue.createApp({
  data() {
    return {
      direction: 'right'
    }
  }
})

app.directive('pin', {
  mounted(el, binding) {
    el.style.position = 'fixed'
    // binding.arg 是我们传递给指令的参数
    const s = binding.arg || 'top'
    el.style[s] = binding.value + 'px'
  }
})

app.mount('#dynamic-arguments-example')
teleport 可以将标签放置到某个元素的子集
app.component('modal-button', {
  template: `
    <button @click="modalOpen = true">
        Open full screen modal! (With teleport!)
    </button>

    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          I'm a teleported modal! 
          (My parent is "body")
          <button @click="modalOpen = false">
            Close
          </button>
        </div>
      </div>
    </teleport>
  `,
  data() {
    return { 
      modalOpen: false
    }
  }
})
放置到body下

插件的使用

import i18nPlugin from './plugins/i18n'
app.use(i18nPlugin, i18nStrings)

watch API 完全等同于组件侦听器 property。watch 需要侦听特定的数据源,并在回调函数中执行副作用。默认情况下,它也是惰性的,即只有当被侦听的源发生变化时才执行回调。

  • watchEffect 比较,watch 允许我们:
    • 懒执行副作用;

    • 更具体地说明什么状态应该触发侦听器重新运行;

    • 访问侦听状态变化前后的值。

Vue3.0

setup包裹所有,传入props root(对应this) torefs 转换数据为响应式数据 reactive 创建类似于data对象 所有data和方法都需要用扩展运算返回