Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2022-7-21技术分享总结 #133

Open
ddd-000 opened this issue Jul 21, 2022 · 5 comments
Open

2022-7-21技术分享总结 #133

ddd-000 opened this issue Jul 21, 2022 · 5 comments

Comments

@ddd-000
Copy link

ddd-000 commented Jul 21, 2022

No description provided.

@ddd-000
Copy link
Author

ddd-000 commented Jul 21, 2022

一、$attrs、$listeners:主要用于实现多层嵌套数据传递

1. $attrs -- 绑定所有属性 (除了props以外

image

2. $listeners ---绑定绑定所有事件

image

3. inheritAttrs

image

举个简单滴栗子~

A组件里面嵌套了B组件,B组件里面嵌套了C组件,我想把A组件的数据传给C

  • 组件A
<template>
<div>
  <h2>组件A{{myData}}</h2>
  <B @changeMyData="changeMyData" :myData="myData" :attrsData="attrsData"></B>
</div>
</template>
<script>
import B from "./B";
export default {
  data() {
    return {
      myData: "100",
      attrsData: "222"
    };
  },
  components: { B },
  methods: {
    changeMyData(val) {
      this.myData = val;
    }
  }
};
</script>
  • 组件B
<template>
  <div>
    <h3>组件B</h3>
    <C v-bind="$attrs" v-on="$listeners"></C>
  </div>
</template>
<script>
import C from "./C";
export default {
  components: { C },
};
</script>
  • 组件C
<template>
  <div>
    <h5>组件C</h5>
    <input v-model="myc" @input="hInput" />
  </div>
</template>
<script>
export default {
  props: { myData: { String } },
  created() {
    this.myc = this.myData;  // 在组件A中传递过来的属性
    console.log(this.$attrs, this.$listeners);  
//打印的结果:{attrsData: '222'}attrsData: "222"[[Prototype]]: Object {changeMyData: ƒ} (没有props的值:myData)
  },
  methods: {
    hInput() {
      this.$emit("changeMyData", this.myc); // // 在组件A中传递过来的事件
    }
  }
};
</script>
  • inheritAttrs使用:
    • 当B没有设置inheritAttrs,默认为true,B会带上a的属性,即使根本用不上
      image
    • 设置完inheritAttrs: false
      image

总结:

  • $listeners:

    • 想要孙组件修改父组件的值:在子组件中绑定v-on="$listeners",
    • 在孙组件中$emit一个事件,父组件接收这个事件可以修改父组件的值
  • $attrs:

    • 父组件绑定了多个属性,孙组件要想直接获取父组件绑定的值,在子组件中绑定v-bind="$attrs" 在孙组件中,
    • this.$attrs中就可看到父组件绑定的除了props传递的属性的所有其他属性的值
  • inheritAttrs:

    • 父组件传递的值 会覆盖子组件自己的属性 ,给子组件设置inheritAttrs: false,子组件就会取自己的值。
    • 官方解释: 默认情况下vue会把父作用域的不被认为props的特性绑定且作为普通的HTML特性应用在子组件的根元素上。

@ddd-000
Copy link
Author

ddd-000 commented Jul 21, 2022

三、redis
https://redis.io/docs/getting-started/

1.关于redis

开源的NOSQL系统之一,使用ANSI c语言编写的key-value存储系统(区别于MySQL的二维表格的形式存储。)用作数据库、缓存、消息代理和流引擎

2.在项目中的使用(nuxt强大的服务端能力)

  • 安装包:
    • connect-redis
    • ioredis
    • express-session
  • nuxt.config.js中配置:
redis: {
    host: 'db.vmovier.cc',
    port: '6379',
    password: '[email protected]',
    keyPrefix: 'user-center-test:session_id_',
    enableOfflineQueue: false,
    db: 6
  }
  • 服务端创建中间件
const session = require('express-session')
const Redis = require('ioredis')
const RedisStore = require('connect-redis')(session)

Object.defineProperty(Redis.prototype, 'ready', {
  get() {
    return this.status === 'ready';
  },
  configurable: true,
  enumerable: true,
})

module.exports = function(config) {
  const client = new Redis(config.redis)
  client.on('error', err => {
    switch (err.code) {
    case 'ECONNRESET':
    case 'EPIPE':
      return;
    }
    console.error('unhandled redis session error', err);
  })

  // session middleware
  const sessionMW = session({
    secret: config.session.secret,
    name: config.session.name,
    resave: false,
    saveUninitialized: true,
    cookie: { 
      ...config.session.cookie,
      secure: 'auto',
    },
    store: new RedisStore({
      client,
    }),
  })

  return function(req, res, next) {
    req.redisStore = client
    sessionMW(req, res, next)
  }
}
  • 引用:在server/index
const session = require('./plugins/session')
const app = express()
app.use(session(config))
  • 然后咱们就可以开心的通过req使用redis了!!
  • 使用:
  1. redis存值操作
req.redisStore.set()
  1. redis取值操作
req.redisStore.get()
  1. redis删除操作
req.redisStore.del()

3. redis在nuxt中的其他应用

redis缓存---解决访问量大的问题
https://www.opensourceagenda.com/projects/nuxt-page-cache-with-redis

@ddd-000
Copy link
Author

ddd-000 commented Jul 21, 2022

四、页面曝光埋点(对视图内可视区域进行数据上报)
IntersectionObserver---浏览器原生提供的构造函数

1.使用

  • 以new的形式声明一个对象,接收callback和options:
const io = new IntersectionObserver(callback, options) 
io.observe(DOM) 

callback:当监听目标发生滚动变化时触发的回调函数

  • 一般会触发两次:刚进入视口-->完全离开视口
  • callback函数的参数(entries)是一个数组,每个成员都是一个 IntersectionObserverEntry 对象
  • IntersectionObserverEntry:提供目标元素的信息,有6个属性
    image

options:用来配置参数

  • threshold属性:决定了什么时候触发回调函数
new IntersectionObserver(
  entries => {/* ... */}, 
  {
    threshold: [0, 0.25, 0.5, 0.75, 1]      //表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。
  }
);
  • root属性:指定目标元素所在的容器节点(即根元素)
  • rootMargin属性:定义根元素的margin,用来扩展或缩小rootBounds这个矩形的大小,从而影响intersectionRect交叉区域的大小
var opts = { 
  root: document.querySelector('.container'),
  rootMargin: "500px 0px" 
};

var observer = new IntersectionObserver(
  callback,
  opts
);
  • 事例:
const options = {   
   root: null,   
   rootMargin: 0,   
   thresholds: 1, 
} 
const io = new IntersectionObserver(entries => {   
  console.log(entries)   // Do something 
}, options) 

// 开始观察
io.observe(document.getElementById('example'));

// 停止观察
io.unobserve(element);

// 关闭观察器
io.disconnect();
  • 埋点上报时机
    使用防抖的方式去上报数据,每次页面滑动,有新的元素进入可视区域,触发IntersectionObserver监听时挂载一个settimeout事件,每次IntersectionObserver先cleartimeout在开启一个计时器
exposeStockList () {
      let exposeList = [] // 页面曝光上报数据
      let exposeTimer = null // 页面上报计时器开关
      const stockCardList = document.querySelectorAll('.stock-list-card-container')
      if (stockCardList) {
        stockCardList.forEach(card => {
          const observer = new IntersectionObserver(entries => {
            const entry = entries[0]
            if (entry.isIntersecting) {
              // 埋点数据处理
              const pageX = Math.round((entry.target.offsetLeft - entry.target.parentNode.offsetLeft + entry.target.offsetWidth) / entry.target.offsetWidth)
              const pageY = Math.round((entry.target.offsetTop - entry.target.parentNode.offsetTop + entry.target.offsetHeight + 16) / (entry.target.offsetHeight + 16))
              // const { x: pageX, y: pageY } = entry.boundingClientRect
              const { id: itemId } = entry.target.dataset
              const itemType = this.isAeStockType
              exposeList.push({
                itemId,
                itemType,
                pageX,
                pageY,
              })
              observer.unobserve(card) // 取消监听

              // 埋点数据上报
              if (exposeTimer) {
                clearTimeout(exposeTimer)
              }
              exposeTimer = setTimeout(() => {
                // console.log('最终上报数据:', exposeList)
                this.$sa.track('searchDisplay', {
                  type: 'display',
                  items: JSON.stringify(exposeList),
                  pageIndex: this.page,
                  $url: window.location.href,
                })
                exposeList = []
              }, 1000);
            }
          }, {
            threshold: 0.4
          });
          observer.observe(card)
        })
      }
    }

csr刷新页面时不会触发新的IntersectionObserver监听,这个时候需要在watch里面重新调用一下事件
神策sdk的使用,字符串过大时神策会自动截断,需要在初始化时设置一个max_string_length

  1. 应用:
    https://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html
  • 惰性加载

  • 无限滚动

@ddd-000
Copy link
Author

ddd-000 commented Jul 21, 2022

五、hover不遮挡---hover显示内容的时候会根据视图做“上、右、下、左”的显示处理

开始之前先要了解几个概念

  1. innerHeight:浏览器窗口的视图高度 (innerWidth)
  2. offsetHeight:该元素的像素高度 (offsetWidth/offsetLeft/offsetRight/offsetTop/offsetBottom)
  3. getBoundingClientRect:提供了元素的大小及其相对于视口的位置
  • 含有6个属性:top,lef,right,bottom,width,height
    • width:元素自身的宽度
    • height:元素自身的高度
    • top:元素顶部距离视图顶部的距离
    • bottom:元素底部距离视图顶部的距离
    • left:元素左部距离视图左部的距离
    • right:元素右部距离视图左部的距离
      image

项目中视频和ae卡片的hover为例
image
hover的pover是在卡片下方显示,当下方放不下的时候会在卡片上方展示
image

主要就是做计算

window.innerHeight - e.target.offsetHeight - e.target.getBoundingClientRect().top > e.target.offsetHeight ? 'bottom' : 'top'
//浏览器视口的高度-元素自身的高度-元素相对于视口的顶部的高度 = 元素底部距离视口底部的高度
//如果该高度大于元素自身的高度,说明pover放的下,所以就放在下方展示;否则就在上方展示

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant