面试必备之如何判断一个网站是否是vue开发的?

5,558 阅读3分钟

面试官:给你一个网站,你如何判断当前网站是否为VUE框架开发的?

我:额。。。项目经过打包构建代码都打乱了无法判断用到的框架

面试官:哦,回去等消息吧

我:

640.gif

怎样识别一个网站用到了哪些技术? 是作为一个初级前端的最最基本的基础技能。

拿到一个网站第一反应肯定是确认一下这个网站是啥技术创建的,然后分析一下这个网站的,想看看网站用了啥技术,如果是vue,开发者用了多少组件?然后分析当前组件编译后源码,才能有效的学习和进步。

常规的方式是装个浏览器插件判断.但这种方式展示的消息不是很多,细节没有,无法定位到源码,又没成就感。

问:如何识别当前网站是否是vue开发

一般技术框架都会在window下挂上一些私有变量,变量以两个下划线开头 vue 也不例外,当我们在控制台输入 __ 时控制台会自动模糊匹配提示出window下有的值。

1686551253725.png

看到没? VUE 出来了!!!

1686551317911.png

明显了, __VUE__ 可以用来判断是否是 vue 开发

问:获取网页上的vue实例

vue的页面有个特征会有个全局的app对象 window.app 储存的是 root 节点, 里面隐藏这一些属性

注意: 这个不能百分百获取成功,但只能保 99%, 默认是 window.app 可以改的

1686550126124.png

可以用 console.dir(window.app) 查看这个

1686550298758.png

里面的 __vue_app__ 就是实例了

1686551498763.png

看到没 window.app.__vue_app__这里面包含了当前网页用到的vue版本和vue上下文

1686551930119.png

注意: 有些网站没有实例比如 https://cn.vuejs.org/

1686552059328.png

问:用了多少组件分别是哪些?

如何判断用了多少组件? 首先想到的方案是获取到 root 节点然后向下遍历

如何获取 root 节点呢?当我们运行 console.dir(window.app) 后有两个下划线开头的变量

其中一个叫 vnode 很明显了,就是 root 节点

1686550298758.png

我们获取到的是 VNode 与组件不一样,VNode节点包含组件 component 获取子组件需要到里面去获取

层关系是 VNode=> component => subTree(下一个VNode)

如果 VNode 下面有有时会出现 children字段 值是个数组包含下一层的 VNode,如果不是数组而是各个对象则改为读取 component

1686554535182.png

递归一下就能获取到所有组件了

问:开发环境下如何获取组件与源码关系

注意: 只在开发环境下有效

看下图

1686554676203.png

VNode 里 type 中有个 __file 字段保存的是源码位置 获取即可

完整代码


(function getAllFilePath (){
  const filePath = {}
  const cmpList = {}
  const noNameCmp = []
  let num = 0

  function cmpCallback(cmp){
    num += 0
    console.log('cmpCallback:',cmp)
    const { subTree, type, component, children } = cmp
    if(type){
      // 有name的组件
      if(type.name){
        if(!cmpList[type.name]){
          cmpList[type.name] = []
        }
        cmpList[type.name].push(cmp)
      }
      // 无name的组件
      if(type.render && !type.name){
        noNameCmp.push(cmp)
      }
      // 开发模式下,获取组件对应的源码文件位置
      if(type.__file) {
        const obj = {
          file: type.__file,
          hmrId:  type.__hmrId,
          scopeId: type.__scopeId,
          VNode: cmp
        }
        // hmrId 应该会有的吧,防止没有加个默认值
        const key = obj.hmrId || `noHmrId_${num}`
        if(!filePath[key]){
          filePath[key] = []
        }
        filePath[key].push(obj)
      };
    };
    if(children && Array.isArray(children)){
      children.forEach(o=>{
        cmpCallback(o)
      })
    }
    const newCmp = component;
    if(newCmp){
      cmpCallback(newCmp)
      return
    }
    // 文本组件没有 subTree 值
    subTree && cmpCallback(subTree)
  }
  // 判断三方是vue页面
  if(!window.__VUE__){
    throw new Error('当前页面非Vue开发')
  }
  cmpCallback(app._vnode)
  console.log('当前页面有name的组件有:', cmpList);
  console.log('当前页面无name的组件有:', noNameCmp);
  console.log('当前页面开发环境下组件与源码文件对应关系:', filePath);
  return {
    filePath,
    cmpList
  }
})()

直接复制代码到控制台运行即可,效果如下:

1686555186496.png

总结:

  1. 判断有元素 id为 app (成功率:30%,react也可能是app)

  2. 判断元素属性是否有 data-v-xxx 这种格式 (成功率:80%)

  3. 判断window.__VUE__ === true (成功率:100%)

  4. 打印 console.dir(window.app)  (成功率:100%,可获得vue版本)

image.png