个人知识点整理-updating

337 阅读4分钟

$attrs

父组件传值给子组件,子组件props中没定义接收(子组件可通过this.$attrs获取),则会流转到孙组件,孙组件可定义props接收。一般配合inheritAttrs: false使用 image.png image.png image.png
使用inheritAttrs区别: 控制attrs是否在DOM中渲染

image.png

image.png

$listeners

孙组件若想触发父组件从而更改父组件数据,通过$listeners从而使emit可以直接触发父组件方法
image.png image.png image.png

根据$attrs和$listeners封装组件

image.png image.png image.png image.png
在孙组件el-table上定义文档提供的方法,然后通过$emit触发父组件中方法,孙组件中使用v-bind="$attrs"和v-on="$listeners"是为了让在父组件中传的值可以在孙组件el-table拥有的属性和方法继续流转下去。tableConfig.propList来源于自己写的表格js配置文件,slot具名插槽如果匹配到则显示插槽,没有就显示标签中间内容
子组件主要就是用来让事件和属性流转到孙组件和添加一些动态插槽或者固定的常用插槽,如status插槽,只要配置文件中写slotName: 'status'就会自动生成相应内容,此时要在计算属性中将此插槽名排除,因为这里获取到的插槽是写在父组件中,而不是子组件中,如果你想扩展一些插槽就可以写在父组件中,为了保持统一,孙组件emit的事件方法名最好和el-table文档中一样,有助于开发效率。
注意
image.png image.png image.png 父组件中接收孙组件emit的方法执行了两次,至于原因盲猜就是孙组件emit的事件name我为了保持原有事件名一致性也叫row-click,所以父组件接收的时候如果孙组件加了$listeners则emit的事件执行一次,el-table的子组件emit的row-click由于$listeners原因(子组件可以跨组件emit父组件)也触发了一次,一共就两次了。
事件触发两次解决办法
1:如果为了事件名统一性,孙组件就不用v-on="$listeners";
2:如果孙组件实在想用v-on="$listeners",那么孙组件emit的事件名直接取个和el-table文档中不一样的名字
3:孙组件直接使用v-on="$listeners",不用定义任何方法如@row-click="rowClick"然后emit传给父组件,直接通过$listeners让elementUI的方法触发事件。
image.png

v-bind (v-bind支持对象写法)

image.png 等价于
image.png

插槽

作用域插槽
slot-scope:(支持解构)是用于获取子组件插槽传的值,通过slot-scope='scope'获取值,后面scope名字随便取,scope.row这个row是子组件在slot上传的值叫row如 <slot :row="data"></slot>
slot-scope在vue2.6版本后已移除,虽然还能用,但vue3已不支持此语法,代替为v-slot <template v-slot:default="slotProps"> (slotProps可自定义名字)其中default可省略,但只要出现多个插槽,还是最好写完整 (v-slot:header 可以被重写为 #header
具名插槽
一个不带 name 的 <slot> 出口会带有隐含的名字“default”。
具名插槽+作用域插槽
如果你想在具名插槽上使用作用域插槽 <slot name='header' :row="data"></slot> 父组件上获取此具名插槽的数据可以写为<template slot="header" slot-scope="scope"> 也可以简写为<template #header="scope">

自定义指令Vue.directive

自定义指令的钩子里面没有vue实例,this指向undefined
bind和inserted的异同
共同点: dom插入都会调用,bind在inserted以前
不同点:bind 时父节点为 null,inserted 时父节点存在。
bind是在dom树绘制前调用,inserted在dom树绘制后调用
update 和 componentUpdatedd的异同
共同点:组件更新都会调用,update在componentUpdated以前
不同点:update 组件更新前的状态;componentUpdated 组件更新后的状态

provide和inject

provide选项应该是一个对象或返回一个对象的函数
inject 选项应该是一个字符串数组,或一个对象
父组件通过provide传值给子组件,子组件通过inject接收,无论子组件层次多深都能接收到(不管是子组件还是孙组件)
image.png image.png image.png
但此种通信方式不是响应式的,也就是父组件更改了数据,子组件中的数据不会更新。想改为响应式可以这样写 image.png

Vue中页面展示markdown文件

image.png 1:首先npm i markdown-it highlight.js和text-loader 2:vue.config.js中配置text-loader

chainWebpack: config => {       
      config.module
      .rule('md')
        .test(/\.md/).use('text-loader').loader('text-loader').options({}).end();
    }

3:创建方法解析并挂载到原型

 const md = new MarkdownIt({
            langPrefix: 'hljs language-',
            breaks: true,
            linkify: true,
            highlight: function(str, lang) {
                if(lang && hljs.getLanguage(lang)){
                    try{
                        return hljs.highlight(str, {language: lang}, true).value
                    }catch(_){
                        console.log(_);
                    }
                }
                return `<pre><code class="hljs language-${lang}">${md.utils.escapeHtml(str)}</code></pre>`
            }
        })
        Vue.prototype.$md = md

4:使用

<template>
     <div v-html="demoCodeIcon" class="markdown"></div>
</template>
import demoCodeIcon from './demo-code-icon.md'
 data() {
         return {
             demoCodeIcon:this.$md.render(demoCodeIcon),
         }
     },

computed属性 set

<template>
  <button @click="setList">set</button>// 通过按钮点击触发 
</template>
computed:{
   list:{
     //只有执行this.list=???这个操作才会触发set方法,否则直接执行get
      set:function(newValue){
      //newValue即通过this.list={b: 2}的操作来对newValue赋值(并不是对list赋值)且触发
      set方法,然后触发get方法
         this.options.push(newValue);
      }
      get:function(){
         return this.options;
      }
   }
}
methods:{
   setList(){
      this.list={b: 2}//并不是把{b: 2} 赋值给list的意思, 而是传参给里面的set函数的参数
      newValue并触发set方法**。
   }
}

vue self修饰符

<div @click="aaa">
      最外层
   <div @click.self="doThis">
    self是写在父组件上的,这样能阻止子组件向上冒泡
    <div @click="handle">最内层</div>
    </div>
 </div>

添加.self修饰符handle方法不会由于冒泡触发doThis方法,但是会触发aaa方法;

微任务宏任务执行顺序

理论上执行顺序宏任务=>同步任务=>微任务=>宏任务;即从script开始进入宏任务进去找同步任务,微任务,宏任务,以此循环至结束 (宏任务中继续找同步,微任务,宏任务)。
但是为方便记忆执行顺序可记为同步任务=>微任务=>宏任务

console.log(1) //同步任务
setTimeout(function() {
   console.log(2)//宏任务 
}) 
new Promise(function (resolve) {
   console.log(3) //同步任务,
   //promise主体内是同步,.then .catch()属于微任务,也就是resolve()和reject()
   resolve() 
}).then(function () {
   console.log(4) //微任务,
}).then(function() {
   console.log(5)//微任务, 
}) 
console.log(6)//同步任务

答案就是 1 3 6 4 5 2

3a06d429af4d47c493bcd80196f452d0_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0.webp

vue.config.js Proxy

前端配置代理(在前端请求node服务器,node服务器再帮我们发送真正的请求)

代理后的接口若没有写ip地址,请求地址默认本机ip即localhost,所以network接口地址显示localhost,后通过node代理服务器去请求代理的地址获取数据

若项目本地端口为8080  
1. 先请求localhost:8080 node代理服务器
2. node代理服务器 帮我们再去请求接口
3. 接口将内容返回给 node代理服务器
4. node代理服务器把内容返给前端
"/api": {
        target: url,
        ws: false, 
      },

如果请求的接口含有api,那么pathRewrite可以不写。axios的baseurl要写为'/api'。或者写为'/',并在接口写'/api'

"/api": {
        target: url,
        ws: false, 
        pathRewrite: {
          "^/api": "",
        },
      },

如果接口中不含有api,则需写pathRewrite,api文件中的接口地址前面需加上api, network中地址会加上这个api,但是实际转发中的代理请求不带。
宗旨:配置代理时由于有proxy的target,所以axios的baseurl就不用再写一遍了,若baseURL写完整地址,那么就不会走代理了。

vue的model属性

允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

解释:组件想使用v-model默认props名是value,事件是input,通过model可更改这些默认值,如可把触发事件改为change事件等。更改后,则此文件内所有v-model的触发事件都是model中定义的事件,与model中props定义的哪个名字无关

model: { prop: 'checked', event: 'change' },
props: { checked: { type: Boolean } },

组件内导航钩子

beforeRouteEnter和beforeRouteUpdate这两个钩子处理动态路由页面很好用
beforeRouteUpdate在当前路由改变,但是该组件被复用时触发,如动态路由。
beforeRouteEnter里不可访问this,可在next中通过vm访问,其实就是this

  beforeRouteEnter(to, from, next) {
    next(vm => {
    
    });
},