vue 组件生命周期钩子详解

2023-11-12

Vue是一个自带组件系统的前端框架。Vue的每一个实例其实就是一个组件,我们在组织我们的页面结构的时候其实就是在定一个一个组件,然后拼装在一起,完成一个复杂的页面逻辑。
组件主要包含:数据,模版,以及链接数据和模版的状态响应系统。除了这些,我们还需要对组件的不同渲染阶段做一些监控,定义一些hook来在不同的组件的不同时刻处理不同的业务。
下面是vue的生命周期钩子的集合:

  var LIFECYCLE_HOOKS = [
    'beforeCreate',
    'created',
    'beforeMount',
    'mounted',
    'beforeUpdate',
    'updated',
    'beforeDestroy',
    'destroyed',
    'activated',
    'deactivated',
    'errorCaptured',
    'serverPrefetch'
  ];
  1. beforeCreate
    beforeCreate 阶段是组件的初始化阶段,主要是对组件进行一些属性的初始化
Vue.prototype._init = function (options) {
      var vm = this;
      // a uid
      vm._uid = uid$3++;
      // a flag to avoid this being observed
      vm._isVue = true;
      // merge options
      if (options && options._isComponent) {
        // optimize internal component instantiation
        // since dynamic options merging is pretty slow, and none of the
        // internal component options needs special treatment.
        initInternalComponent(vm, options);
      } else {
        // 合并一些初始化参数
        vm.$options = mergeOptions(
          resolveConstructorOptions(vm.constructor),
          options || {},
          vm
        );
      }
      /* istanbul ignore else */
      {
        // proxy vm上的属性的get set 注入无值的警告信息
        initProxy(vm);
      }
      // expose real self
      vm._self = vm;
      // 初始生命周期标示参数等
      initLifecycle(vm);
      // 初始事件相关的一些参数
      initEvents(vm);
      // 初始化render相关的一些方法属性等
      initRender(vm);
      // 从这行代码往上就是beforeCreate周期需要干的事情
      callHook(vm, 'beforeCreate'); 
  1. created
    created 是初始化阶段,主要是处理组件的options上的参数,创建一些数据响应逻辑
// 处理inject的数据

initInjections(vm); // resolve injections before data/props
// 初始化处理 data属性 props methods watch computed 等,并添加observe
initState(vm);
// 处理provide 数据
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created');

学习Inject和Provide

  1. beforeMount
    处理完上面两步,就开始准备进行挂载,将组件渲染挂载到真实的dom上,在挂载前还要进行一些处理
  Vue.prototype.$mount = function (
    el,
    hydrating
  ) {
    el = el && inBrowser ? query(el) : undefined;
    return mountComponent(this, el, hydrating)
  };
Vue.prototype.$mount = function (
    el,
    hydrating
  ) {
    el = el && inBrowser ? query(el) : undefined;
    return mountComponent(this, el, hydrating)
  };
var mount = Vue.prototype.$mount;
Vue.prototype.$mount = function (
    el,
    hydrating
  ) {
    el = el && query(el);
    // 组件不能挂载在body和html上
    if (el === document.body || el === document.documentElement) {
      warn(
        "Do not mount Vue to <html> or <body> - mount to normal elements instead."
      );
      return this
    }

    var options = this.$options;
    // resolve template/el and convert to render function
    if (!options.render) {
      var template = options.template;
      if (template) {
        if (typeof template === 'string') {
          if (template.charAt(0) === '#') {
            template = idToTemplate(template);
            /* istanbul ignore if */
            if (!template) {
              warn(
                ("Template element not found or is empty: " + (options.template)),
                this
              );
            }
          }
        } else if (template.nodeType) {
          template = template.innerHTML;
        } else {
          {
            warn('invalid template option:' + template, this);
          }
          return this
        }
      } else if (el) {
        // 获取组件对应的dom模版
        template = getOuterHTML(el);
      }
      if (template) {
        /* istanbul ignore if */
        if (config.performance && mark) {
          mark('compile');
        }
		// 生成模版语法树
        var ref = compileToFunctions(template, {
          outputSourceRange: "development" !== 'production',
          shouldDecodeNewlines: shouldDecodeNewlines,
          shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
          delimiters: options.delimiters,
          comments: options.comments
        }, this);
        // render方法
        var render = ref.render;
        var staticRenderFns = ref.staticRenderFns;
        options.render = render;
        options.staticRenderFns = staticRenderFns;

        /* istanbul ignore if */
        if (config.performance && mark) {
          mark('compile end');
          measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
        }
      }
    }
    return mount.call(this, el, hydrating)
  };
  
function mountComponent (
    vm,
    el,
    hydrating
  ) {
    vm.$el = el;
    if (!vm.$options.render) {
      vm.$options.render = createEmptyVNode;
      {
        /* istanbul ignore if */
        if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
          vm.$options.el || el) {
          warn(
            'You are using the runtime-only build of Vue where the template ' +
            'compiler is not available. Either pre-compile the templates into ' +
            'render functions, or use the compiler-included build.',
            vm
          );
        } else {
          warn(
            'Failed to mount component: template or render function not defined.',
            vm
          );
        }
      }
    }
    // 以上为beforeMount前做的事情
    callHook(vm, 'beforeMount');
  1. mounted
    当数据处理完毕,虚拟语法树也建好了,接下来就是将语法树生成虚拟dom树,然后更新到真实dom里去。虚拟dom树算法
    var updateComponent;
    /* istanbul ignore if */
    if (config.performance && mark) {
      updateComponent = function () {
        var name = vm._name;
        var id = vm._uid;
        var startTag = "vue-perf-start:" + id;
        var endTag = "vue-perf-end:" + id;

        mark(startTag);
        var vnode = vm._render();
        mark(endTag);
        measure(("vue " + name + " render"), startTag, endTag);

        mark(startTag);
        vm._update(vnode, hydrating);
        mark(endTag);
        measure(("vue " + name + " patch"), startTag, endTag);
      };
    } else {
      updateComponent = function () {
        vm._update(vm._render(), hydrating);
      };
    }

    // we set this to vm._watcher inside the watcher's constructor
    // since the watcher's initial patch may call $forceUpdate (e.g. inside child
    // component's mounted hook), which relies on vm._watcher being already defined
    // 创建render watcher,调用组件render方法
    new Watcher(vm, updateComponent, noop, {
      before: function before () {
        if (vm._isMounted && !vm._isDestroyed) {
          callHook(vm, 'beforeUpdate');
        }
      }
    }, true /* isRenderWatcher */);
    hydrating = false;

    // manually mounted instance, call mounted on self
    // mounted is called for render-created child components in its inserted hook
    if (vm.$vnode == null) {
      vm._isMounted = true;
      // 如果是第一次挂载,触发mounted
      callHook(vm, 'mounted');
    }

mounted后,就可以获取到组件对应的真实dom

  1. beforeDestroy
    当组件销毁的准备销毁的时候,会先触发该钩子函数
Vue.prototype.$destroy = function () {
      var vm = this;
      if (vm._isBeingDestroyed) {
        return
      }
      callHook(vm, 'beforeDestroy');
  1. destroyed
    销毁完的钩子,在执行该钩子前,会清空一些如watcher,事件,删除dom等动作。
vm._isBeingDestroyed = true;
      // remove self from parent
      var parent = vm.$parent;
      if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
        remove(parent.$children, vm);
      }
      // teardown watchers
      if (vm._watcher) {
        vm._watcher.teardown();
      }
      var i = vm._watchers.length;
      while (i--) {
        vm._watchers[i].teardown();
      }
      // remove reference from data ob
      // frozen object may not have observer.
      if (vm._data.__ob__) {
        vm._data.__ob__.vmCount--;
      }
      // call the last hook...
      vm._isDestroyed = true;
      // invoke destroy hooks on current rendered tree
      // 删除dom
      vm.__patch__(vm._vnode, null);
      // fire destroyed hook
      callHook(vm, 'destroyed');
  Watcher.prototype.teardown = function teardown () {
    if (this.active) {
      // remove self from vm's watcher list
      // this is a somewhat expensive operation so we skip it
      // if the vm is being destroyed.
      if (!this.vm._isBeingDestroyed) {
        remove(this.vm._watchers, this);
      }
      var i = this.deps.length;
      while (i--) {
        this.deps[i].removeSub(this);
      }
      this.active = false;
    }
  };
  1. beforeUpdate
    当数据更新触发模版更新的时候,会调用watcher的render函数,调用前会先触发watcher的before参数里的内容。
new Watcher(vm, updateComponent, noop, {
      before: function before () {
        if (vm._isMounted && !vm._isDestroyed) {
          callHook(vm, 'beforeUpdate');
        }
      }
    }, true /* isRenderWatcher */);
function flushSchedulerQueue () {
    currentFlushTimestamp = getNow();
    flushing = true;
    var watcher, id;

    // Sort queue before flush.
    // This ensures that:
    // 1. Components are updated from parent to child. (because parent is always
    //    created before the child)
    // 2. A component's user watchers are run before its render watcher (because
    //    user watchers are created before the render watcher)
    // 3. If a component is destroyed during a parent component's watcher run,
    //    its watchers can be skipped.
    queue.sort(function (a, b) { return a.id - b.id; });

    // do not cache length because more watchers might be pushed
    // as we run existing watchers
    for (index = 0; index < queue.length; index++) {
      watcher = queue[index];
      if (watcher.before) {
        watcher.before();
      }
  1. updated
    updated 是把所有订阅的watcher的update方法全部执行完后触发。
function flushSchedulerQueue () {
    currentFlushTimestamp = getNow();
    flushing = true;
    var watcher, id;

    // Sort queue before flush.
    // This ensures that:
    // 1. Components are updated from parent to child. (because parent is always
    //    created before the child)
    // 2. A component's user watchers are run before its render watcher (because
    //    user watchers are created before the render watcher)
    // 3. If a component is destroyed during a parent component's watcher run,
    //    its watchers can be skipped.
    queue.sort(function (a, b) { return a.id - b.id; });

    // do not cache length because more watchers might be pushed
    // as we run existing watchers
    for (index = 0; index < queue.length; index++) {
      watcher = queue[index];
      if (watcher.before) {
        // 这里执行beforeupdate 钩子
        watcher.before();
      }
      id = watcher.id;
      has[id] = null;
      watcher.run();
      // in dev build, check and stop circular updates.
      if (has[id] != null) {
        circular[id] = (circular[id] || 0) + 1;
        if (circular[id] > MAX_UPDATE_COUNT) {
          warn(
            'You may have an infinite update loop ' + (
              watcher.user
                ? ("in watcher with expression \"" + (watcher.expression) + "\"")
                : "in a component render function."
            ),
            watcher.vm
          );
          break
        }
      }
    }

    // keep copies of post queues before resetting state
    var activatedQueue = activatedChildren.slice();
    var updatedQueue = queue.slice();

    resetSchedulerState();

    // call component updated and activated hooks
    callActivatedHooks(activatedQueue);
    callUpdatedHooks(updatedQueue);

    // devtool hook
    /* istanbul ignore if */
    if (devtools && config.devtools) {
      devtools.emit('flush');
    }
  }

  function callUpdatedHooks (queue) {
    var i = queue.length;
    while (i--) {
      var watcher = queue[i];
      var vm = watcher.vm;
      if (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {
        //执行updated 钩子
        callHook(vm, 'updated');
      }
    }
  }

下面的两个钩子是和keep-alive有关的
9. activated

function activateChildComponent (vm, direct) {
    if (direct) {
      vm._directInactive = false;
      if (isInInactiveTree(vm)) {
        return
      }
    } else if (vm._directInactive) {
      return
    }
    if (vm._inactive || vm._inactive === null) {
      vm._inactive = false;
      for (var i = 0; i < vm.$children.length; i++) {
        //所有的子节点会先触发activated
        activateChildComponent(vm.$children[i]);
      }
      callHook(vm, 'activated');
    }
  }
  1. deactivated
function deactivateChildComponent (vm, direct) {
    if (direct) {
      vm._directInactive = true;
      if (isInInactiveTree(vm)) {
        return
      }
    }
    if (!vm._inactive) {
      vm._inactive = true;
      for (var i = 0; i < vm.$children.length; i++) {
        //所有的子节点会先触发deactivated
        deactivateChildComponent(vm.$children[i]);
      }
      callHook(vm, 'deactivated');
    }
  }
  1. errorCaptured
function handleError (err, vm, info) {
    // Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
    // See: https://github.com/vuejs/vuex/issues/1505
    pushTarget();
    try {
      if (vm) {
        var cur = vm;
        while ((cur = cur.$parent)) {
          var hooks = cur.$options.errorCaptured;
          if (hooks) {
            for (var i = 0; i < hooks.length; i++) {
              try {
                var capture = hooks[i].call(cur, err, vm, info) === false;
                if (capture) { return }
              } catch (e) {
                globalHandleError(e, cur, 'errorCaptured hook');
              }
            }
          }
        }
      }
      globalHandleError(err, vm, info);
    } finally {
      popTarget();
    }
  }

捕获子组件异常的钩子
12. serverPrefetch
服务端渲染的一个钩子

下面再讲一下组件生命周期的钩子的执行顺序
1.单个组件的
beforeCreate
created
beforeMount
mounted
如果有更新
beforeUpdate
updated
如果销毁
beforeDestroy
destroyed

如果是切换 keep-alive的组件
显示的时候触发activated
异常的时候触发 deactivated

2.嵌套组件
父beforeCreate
父created
父beforeMount
子beforeCreate
子created
子beforeMount
子mounted
父mounted

销毁的时候
父beforeDestroy
子beforeDestroy
子destroyed
父destroyed

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue 组件生命周期钩子详解 的相关文章

  • vue实现 marquee(走马灯)

    样式 代码 div class marquee prompt div class list prompt span class prompt item span div div data return listPrompt xxx xxxx
  • 30天精通Nodejs--第十九天:express-文件上传下载

    目录 前言 环境准备与依赖安装 文件上传功能实现 引入并配置express fileupload中间件 注意事项 文件下载功能实现 结语 前言 文件的上传和下载是许多应用程序必备的功能 Node js的Express框架同样可以通过集
  • gitolite hooks - 接收后似乎不起作用

    我在我的仓库中配置了 gitolite 我看到了 gitolite 文献中记录的 2 个钩子副本 我希望服务器端挂钩 post receive 在有人推送到存储库时发送电子邮件 我正在使用 git notifier 但是 当我推动时什么也没
  • 考虑光伏出力利用率的电动汽车充电站能量调度策略研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据
  • 如何在 Python 脚本中使用 Google OAuth2

    在使用 Python 脚本将视频上传到 YouTube 频道时 若希望将视频上传到第二个频道 需要解决 OAuth2 授权的问题 解决方案 创建新的 Google Cloud 项目 from google oauth2 import ser
  • Android 相当于 iOS MobileSubstrate 风格的挂钩吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在 WordPress 中设置动态 `home` 和 `siteurl`?

    我使用动态配置多语言设置locale筛选 其中获取子域名来确定语言 function load custom language locale get the locale code according to the sub domain n
  • Windows 8 Metro 风格应用程序和窗口挂钩

    我对 window hooks 和 Windows 8 Metro 应用程序都很陌生 我想开发一个后台服务 流程 检查用户刚刚点击启动的 Metro 应用程序的 属性 例如播放音乐的应用程序 文本文档创建应用程序 根据找到的属性 激活其他应
  • 低级键盘挂钩

    我刚刚买了一个新键盘 我有兴趣准确跟踪键盘整个使用寿命期间我按下 敲击的次数 我只想记录 keyUp 因为我不关心重复 我一直在搜索最好的方法来做到这一点 但我什至不知道该采取什么方法 所以我在智能搜索方面遇到了困难 另外 我真正使用过的唯
  • 注册一个全局钩子,检测鼠标是否拖动文件/文本

    我知道有可能为鼠标注册全局钩子 http www codeproject com KB cs globalhook aspx移动 按钮单击 滚动等 但我想知道是否有任何方法可以检测用户是否实际上使用全局挂钩拖动文件或文本 或其他内容 似乎找
  • 如何为钩子创建蹦床函数

    我对挂钩很感兴趣 我决定看看是否可以挂钩一些函数 我对使用 detours 这样的库不感兴趣 因为我想拥有自己做的经验 通过我在互联网上找到的一些资源 我能够创建下面的代码 这是基本的 但效果还不错 然而 当挂钩由多个线程调用的函数时 它被
  • 无法从 Git post-receive hook 检测分支

    我在远程存储库上设置了一个后接收挂钩 它尝试确定传入推送的分支名称 如下所示 branch git rev parse abbrev ref HEAD 不过 我发现无论我从 branch 变量推送哪个分支 都会设置为 master 有任何想
  • 在 Woocommerce 中将 Avada Catalog 排序挂钩覆盖回默认值

    我正在尝试通过将以下代码添加到 Avada child 来修改 Woocommerce 排序选项以获得自定义排序选项function php file add custom sorting option add filter woocomm
  • 如何在Windows平台上编写Git Server Hooks?

    我找不到任何适用于 Windows 的 Git 挂钩的明确示例 我在 Windows Server 上使用 Bonobo Git Server 我需要预提交和提交后挂钩作为 cmd 或 bat 预提交应检查空注释 提交后应发送有关提交的电子
  • Mercurial hook 的操作类似于“changegroup”,但仅在推送时?

    我们已经构建了一个变更集传播机制 但它依赖于捆绑和解除捆绑新变更集 如果我们要使用changegroup钩子 那么它会导致循环行为 因为钩子是运行的在拉 推或解绑期间 http mercurial selenic com wiki Hook
  • 全局键盘挂钩的合法用途是什么?

    除了仅应由操作系统提供的应用程序启动快捷方式之外 Windows 键盘挂钩等东西的合法用途是什么 在我看来 我们只在键盘记录器之类的事情上遇到问题 因为操作系统提供了钩子来执行除操作系统内核本身之外的任何情况下任何人都不允许执行的操作 编辑
  • 防止 DLL 文件通过 MS Detours 加载到我的进程中

    我想阻止特定的第三方 DLL 文件在运行时加载到我的应用程序进程中 我最初的尝试是使用 MS Detours 产品 我有一个32位的MFC http en wikipedia org wiki Microsoft Foundation Cl
  • git Push Remote:警告:hooks.mailinglist 有多个值

    我刚刚从使用 gitosis 升级到 gitolite 电子邮件通知适用于所有存储库 但对于 gitolite admin 存储库 我在推送时收到此警告 推送很好 git push remote warning hooks announce
  • 是否有 Subversion Checkout Hook 或类似的东西?

    我正在使用 subversion 存储库 并且我想知道何时有人要求我的存储库签出 就像 svn co 或 svn up 每当有人从我的 svn 服务器请求信息时 是否可以使用挂钩或其他方法来运行脚本或发送电子邮件 如何在不依赖 apache
  • 詹金斯钩子不工作 - 詹金斯位桶

    您好 我正在使用 jenkins 和 bitbucket 当我向 bitbucket 存储库提交任何内容时 我想触发 jenkins 中的构建 在詹金斯 我创建了一个名为test 1 在配置部分Build Triggers我勾选的部分Tri

随机推荐

  • MATLAB BP神经网络预测算法

    内容 BP神经网络是一种多层前馈网络 可以进行学习和存储输入输出映射关系 不需要建立数学方程式 BP神经网络预测算法预测序号15的跳高成绩 下表是国内男子跳高运动员各项素质指标 P 3 2 3 2 3 3 2 3 2 3 4 3 2 3 3
  • [洛谷] [NOIP2018 提高组] 旅行 加强版 - 基环树

    题目链接 https www luogu com cn problem P5049 题目描述 小 Y 是一个爱好旅行的 OIer 她来到 X 国 打算将各个城市都玩一遍 小Y了解到 X国的 n 个城市之间有 m 条双向道路 每条双向道路连接
  • d3dcompiler_43.dll缺失怎么修复方法_d3dcompiler43dll丢失怎么解决

    懂电脑的人都知道 dll文件是电脑运行各种程序的根本 少了它的话无论什么软件 游戏都运行不了 但是dll文件又并不只有一种 其中最常丢失的是这款d3dcompiler 43 dll文件 这款文件是运行电脑系统的关键 也是运行电脑上常用程序的
  • Go 语法 变量

    文章目录 简介 一些语法 go 数据类型 demo code 简介 go的一个思想 一个问题尽量只有一个解决方案是最好的 go 中函数是第一等元素 studygolang com pkgdoc go build src go 编译 go r
  • Vulkan同步机制和图形-计算-图形转换的风险(一)

    在现代渲染环境中 很多情况下在一个数据帧期间会产生计算负荷 在GPU上计算通常 非固定功能 是并行编程的 通常用于具有挑战性 完全不可能或仅通过标准图形管道 顶点 几何 细化 栅格 碎片 实现的效率低下的技术 一般情况下 计算在实现技术方面
  • scrollIntoView() 方法实现元素滚动

    TOC scrollIntoView 方法实现元素滚动 element scrollIntoView Element 接口 dom元素 的 scrollIntoView 方法会滚动元素的父容器 使被调用 scrollIntoView 的元素
  • python更多语法

    本文译自https docs python org 2 7 tutorial 完全是出于个人兴趣翻译的 请勿追究责任 另外 谢绝商业牟利 刊印请与本人和原作者联系 无授权不得刊印 违者必究其责任 如需转发 请注明来源 并保留此行 尊重本人的
  • Mac环境下配置JAVA_HOME

    Mac环境下配置JAVA HOME 1 下载JDK版本 JDK官方下载地址 Java下载地址 下载旧版本需要注册oracle用户 下载jdk 12 0 2 osx x64 bin dmg并点击安装 嫌浏览器下载慢的可以把下载地址粘贴到迅雷中
  • Tomcat配置HTTPS访问

    在tomcat中存在两种证书验证情况 1 单向验证 2 双向验证 1 tomcat单向认证 服务器端会提供一个公开的公钥 每一个访问此服务器的客户端都可以获得这个公钥 此公钥被加密后 服务器端可以进行解密处理 之后验证是否配对 配置 在此次
  • postgresql使用UUID函数gen_random_uuid()

    PostgreSQL 13版本前不提供生成UUID数据的内置函数 如果需要使用UUID数据 可通过创建外部扩展 uuid ossp或 pgcrypto生成 UUID数据 PostgreSQL 13 新增gen random uuid 内置函
  • 下载JDK并配置JDK环境变量

    1 下载JDK8或者JDK11 1 点击链接进入官网下载页面 https www oracle com java technologies downloads java8 下拉页面一直到下载的地方 在这里可以选择是下载JDK8还是JDK11
  • 判断某个数组是否包含在另一个数组中

    判断b数组是否包含在a数组中 function isContained a b if a instanceof Array b instanceof Array return false if a length lt b length re
  • 打开cmd闪退

    我们在使用电脑过程中一般会很少用到cmd命令 CMD命令窗口在一些特殊情况时我们会用到 如PING下看网络通不通 在CMD窗口里运行命令如磁盘格式转换 但是有些朋友遇到了这样的问题 在开始运行输入CMD回车后 CMD命令黑框框出来闪一下就消
  • 使用“VMware ThinApp”绿化软件

    当我看到 WPS Office 在我的电脑中写入了上万条注册表项时 我几乎要崩溃了 这个 有点太多了吧 软件绿化工具 环境 Workstation 15 5 Player for Windows 绿化软件 VMware ThinApp 软件
  • 纹波电压

    什么是纹波电压 狭义上的纹波电压 是指输出直流电压中含有的工频交流成分 直流电压本来应该是一个固定的值 但是很多时候它是通过交流电压整流 滤波后得来的 由于滤波不彻底 就会有剩余的交流成分 下图为1 8V的纹波电压 纹波电压是如何产生的 首
  • 2022年Python笔试选择题及答案(秋招)

    2022年Python笔试选择题及答案 秋招 单选题 1 以下关于 Python 的描述错误的是 A Python 的语法类似 PHP B Python 可用于 Web 开发 C Python 是跨平台的 D Python 可用于数据抓取
  • 网络编程day7作业

    将词典导入数据库 include
  • Unity 空格会触发Button的问题

    问题 做了一个界面 空格可以召唤或者关闭一个面板 上面有Button可以控制人物数量信息 当点击过Button修改数量 再按下空格隐藏面板后 最后点击的Button就会被空格键触发一次 如下图 解决 这是由于Button中Navigatio
  • PAT乙级题解—— 1071 小赌怡情 (15分)

    常言道 小赌怡情 这是一个很简单的小游戏 首先由计算机给出第一个整数 然后玩家下注赌第二个整数将会比第一个数大还是小 玩家下注 t 个筹码后 计算机给出第二个数 若玩家猜对了 则系统奖励玩家 t 个筹码 否则扣除玩家 t 个筹码 注意 玩家
  • vue 组件生命周期钩子详解

    Vue是一个自带组件系统的前端框架 Vue的每一个实例其实就是一个组件 我们在组织我们的页面结构的时候其实就是在定一个一个组件 然后拼装在一起 完成一个复杂的页面逻辑 组件主要包含 数据 模版 以及链接数据和模版的状态响应系统 除了这些 我