vue注意事项记录

500 阅读3分钟

SFC 语法规范

*.vue 件都由三种类型的顶层语法块所组成:<template><script><style>


<template>

  • 每个 *.vue 文件最多可同时包含一个顶层 <template> 块。
  • 其中的内容会被提取出来并传递给 @vue/compiler-dom,预编译为 JavaScript 的渲染函数,并附属到导出的组件上作为其 render 选项。

<script>

  • 每一个 *.vue 文件可以有多个 )。
  • 该脚本将作为 ES Module 来执行。
  • 其默认导出的内容应该是 Vue 组件选项对象,它要么是一个普通的对象,要么是 defineComponent 的返回值。

<script setup>

  • 每个 *.vue 文件最多只能有一个 <script setup> 块 (不包括常规的
  • 该脚本会被预处理并作为组件的 setup() 函数使用,也就是说它会在每个组件实例中执行。

<style>

  • 一个 *.vue 文件可以包含多个 <style> 标签。
  • <style> 标签可以通过 scopedmodule attribute (更多详情请查看 SFC 样式特性) 将样式封装在当前组件内。多个不同封装模式的 <style> 标签可以在同一个组件中混

未编译模板闪烁

使用v-cloak

<style>
[v-cloak]{
  display:none;
}
</style>
<template>
  <div id="#app" v-cloak>{{ msg }} </div>
</template>

避免使用 v-html

在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞。请仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容(script也属于HTML内容)。

属性绑定 v-bind:attrName / :attrName

如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

事件修饰符

事件修饰符的先后顺序不同,执行的效果也会有所不同

条件渲染

一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

想要切换不止一个元素,在这种情况下我们可以在一个 <template>元素上使用 v-if,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个 <template> 元素。==>template是一个空标签

不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-show 不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。

列表渲染

v-for渲染时要加:key= 唯一值,这里的唯一值一般为后端传来的id即可,若v-forv-if作用于同一个标签上,在v2中,v-for的优先级比v-if要高,v3则相反.

强烈不建议放在同一标签上!!!

表单输入绑定

v-model 会忽略任何表单元素上初始的 valuecheckedselected 属性。它将始终将当前绑定的 JavaScript 状态视为数据的正确来源。你应该在 JavaScript 中使用data 选项来声明该初始值。

多选框建议值设置为数组,开关建议值设置为boolean类型.

计算属性computed

计算属性默认仅能通过计算函数得出结果。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建

computed:{
  reverseMsg(){
    // 警告warn :readonly ! ! !
    return this.msg.split('').reverse().join('') 
  }
}

computed:{
  fullName:{
    get(){
         return this.firstName + ' ' + this.lastName
    },
    set(val){
       this.firstName = newValue.split(' ')[0]
       this.lastName = newValue.split(' ')[1]
    }
  }
}

侦听器watch

使用场景:数据变化时执行异步或开销比较大的操作。

watch默认是浅层响应,仅会监听第一层,若想监听深层数据,可用配置项deep:true.若刚开始就想监听数据,可以使用immediate:true.若想达到某一个条件下再开启监听,需要使用 this.$watch(监听的数据,callback)手动去添加侦听器.

如果不使用深度侦听,如何监听对象下的属性的变化?可以通过 监听 对象.属性的变化

总的来说, watch用于监听数据的变化并执行自定义操作,而 computed用于计算基于依赖数据的属性.

vue3组合式API中的watch第一个参数默认只能为对象,若需要监听某个值可以写为 [arg1,arg2] (=>obj.keyName) 这种写法

单向数据流

父组件通过props传递给子组件的数据,子组件无法对其进行更改,称之为单向数据流.

注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。

属性透传

父组件子组件标签的属性,默认会透传到子组件根元素上,可用props来接收或设置inheirtAttrs:false,借助v-bind="$attrs"可指定透传到子组件的某个标签上

<template id="button">
  <!-- Attributes 继承(class, v-on事件继承) -->
  <div class="button">
    <div >测试</div>
    <!--借助v-bind指令可以让透传的属性放在button中-->
    <button class="btn" v-bind="$attrs">按钮</button>
  </div>
</template>

router-link的active-class

默认情况下,Vue Router的路由匹配是基于前缀的,所以如果当前路由是/,它将匹配所有以/开头的路由。通过添加exact属性,我们确保只有当路由完全匹配时才应用active-class

<template>
  <div id="app">
    <nav>
      <router-link to="/" exact active-class="active">Home</router-link>
      <router-link to="/about" exact active-class="active">About</router-link>
      <router-link to="/mine" exact active-class="active">Mine</router-link>
    </nav>
    <router-view />
  </div>
</template>

<style>
.active {
  font-weight: bold;
  color: red;
}
</style>

动态组件 :is

使用<component :is="templateName">指定组件,如果想让组件保持存活状态,可以使用<keepAlive>,默认为全部缓存, 且任何时候都只有一个活跃组件示例作为<keepAlive>的直接子节点.

当一个组件在 中被切换时,它的 activated 和 deactivated 生命周期钩子将被调用,用来替代 mounted 和 unmounted。

可使用include / exclude制定组件中的name来确定要被缓存的组件,组件如果想要条件性地被KeepAlive 缓存,就必须显式声明一个 name 选项。

DOM 模板解析注意事项(is="vue:组件名")

若模板标签为tr,但是,在这种用例中,你可能需要 Vue 用其组件来替换原生元素,你可以在 is 的值中加上 vue: 前缀,这样 Vue 就会把该元素渲染为 Vue 组件(my-row-component为自定义组件):

<table>
  <tr is="vue:my-row-component"></tr>
</table>

依赖注入

provide的数据不会保持数据响应性,可使用computed(callback)的方式来保持数据响应性.

 count: computed(() => this.count) // 响应式关键

如果我们想要用一个不同的本地属性名注入该属性,我们需要在 inject 选项的属性上使用对象的形式:

{
    inject: {
         /* 本地属性名 */ localMessage: {
           from: /* 注入来源名 */ 'message'
         }
    }
}

这里,组件本地化了原注入名 message 所提供的的属性,并将其暴露为this.localMessage

默认情况下,inject假设传入的注入名会被某个祖先链上的组件提供。如果该注入名的确没有任何组件提供,则会抛出一个运行时警告。

如果在注入一个值时不要求必须有提供者,那么我们应该声明一个默认值,和 props 类似:

{
    // 当声明注入的默认值时,必须使用对象形式
    inject: {
     message: {
       from: 'message', // 当与原注入名同名时,这个属性是可选的
       default: 'default value'
     },
     user: {
       // 对于非基础类型数据,如果创建开销比较大,或是需要确保每个组件实例
       // 需要独立数据的,请使用工厂函数
       default: () => ({ name: 'John' })
     }
    }
}

混入Mixins

除了生命周期钩子函数外,所有的代码都以组件为优先,生命周期钩子函数先执行混入的,后执行组件的.

尽量避免全局混入的使用!!!

路由未匹配路径

{
  path: '/404',
    name: '404',
    component: () => import('@/view/NotFound.vue')
},
  {
    path: '/:catchAll(.*)*',
      redirect: '/404'
  }

路由守卫

路由守卫方法都需要进行next放行或return

全局路由守卫

路由访问之前 beforeEach(to,from,next)

const routers = createRouter({
    history: createWebHashHistory(),
    routes
})
  routers.beforeEach(to,from,next){
  }

路由访问之后 afterEach(to,from,next)

const routers = createRouter({
    history: createWebHashHistory(),
    routes
})
  routers.afterEach(to,from,next){
  }

局部路由钩子

局部路由访问之前 beforeEnter

beforeEnter(to,from,next){
  next('routerPath')
}

局部组件路由钩子

组件路由访问之前 beforeRouterEnter

beforeRouterEnter(to,from,next)

组件路由改变时 beforeRouterUpdate

beforeRouterUpdate(to,from,next)

组件路由组件访问之后 beforeRouterLeave

beforeRouterLeave(to,from,next)

meta

<!-- 路由组件中: -->
meta:{
 keyName:value
}
// view层:
$route.meta.keyName

vuex

module写法需要在状态模块中添加配置项

{
  namespaced:true
}

辅助函数

import{mapState,mapGetters,mapMutations,mapActions} from 'vuex'

mapState / mapGetters 均为一个对象,需要用扩展运算符 ... 在computed中展开

mapState

与组件的data()类似,用来存储状态标识

computed:{
  ...mapState('moduleName',['stateKeyName','stateKeyName2'])
}

mapGetters

与组件的computed计算属性类似

computed:{
  ...mapGetters('moduleName',['gettersFunctionName','gettersFunctionName2'])
}

mapMutations / mapActions 均为一个对象,需要用扩展运算符 ... 在methods中展开

mapMutations

用来管理同步状态变化

methods:{
  ...mapMutations('moduleName',['mutationsFunctionName','mutationsFunctionName2'])
}

mapActions

mapActions 提交commit的是 mapMutations中的mutationsFunctionName ,而不是直接变更状态。

用来管理异步状态变化

methods:{
  ...mapActions('moduleName',['actionsFunctionName','actionsFunctionName2'])
}

css样式覆盖问题

若组件嵌套层次过深,可使用:deep(css选择器)进行修改

body{
  :deep(p,span,.class,#id){
    color:red
  }
}