news 2026/8/19 10:36:22

Vue2-week2

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue2-week2

组件(实现应用中局部功能代码和资源的集合)

data写成函数式浅拷贝其中一组发生变化后另一个不变

Vue2 组件基础 & 组件嵌套 代码笔记梳理

你贴了两段原生 Vue2(非脚手架)代码:

  1. 第一段:组件的定义、全局注册、局部注册、组件使用
  2. 第二段:组件嵌套,组件内部注册子组件

一、组件三大步骤(第一段代码核心)

  1. 定义组件Vue.extend(配置对象)

⚠️组件配置对象和new Vue()区别两点

  • 不要写el:由 Vue 实例 vm 的el决定挂载哪个容器
  • data必须是函数data(){ return {} },防止多个组件实例共用一份对象引用,改一个全部都变
  • template写组件 HTML 结构,只能一个根容器包裹
const school = Vue.extend({ template:`<div>...</div>`, data(){ return { schoolName:'尚硅谷' } }, methods:{} }) //简写:可以省略Vue.extend,直接写对象 const school = { template:`<div>...</div>`, data(){return{}} }
  1. 注册组件
  • 全局注册Vue.component('组件标签名',组件对象),所有 vm 实例都可以直接用
Vue.component('hello', hello)
  • 局部注册:在 new Vue 的components配置里注册,仅当前 vm 容器可用
new Vue({ el:'#root', components:{ xuexiao: school, //key:页面写的标签名,value:组件对象 xuesheng: student } })
  1. 使用组件:页面写标签<xuexiao></xuexiao>

注意:无脚手架环境,不要自闭合<xuexiao/>,会导致后面 DOM 渲染失效,必须成对闭合。

组件名规则

  1. 单个单词:school/School
  2. 多单词:
    • 短横线命名my‑school(原生浏览器直接可用)
    • 大驼峰MySchool只能脚手架环境使用,原生 html 不识别
  3. 不要和原生 html 重名,比如divh1
  4. name配置:给 vue 开发者工具显示组件名字,不影响页面标签使用

二、组件嵌套(第二段代码)

核心:子组件在父组件的 components 中局部注册,父组件 template 中直接写子组件标签

执行顺序:

  1. 定义 student 子组件
  2. 定义 school 父组件,在它内部components:{student}注册子组件,template 写<student></student>
  3. app 组件引入 school、hello 组件
  4. Vue 实例 vm,不写大量标签,直接用template:'<app></app>',挂载#root
const school = Vue.extend({ template:` <div> <h2>学校:{{name}}</h2> <student></student> <!-- 使用子组件 --> </div> `, components:{ student } //在父组件内部注册子组件 })

整体层级关系:

vm(Vue实例) └── app组件 ├─ hello组件 └─ school组件 └─ student组件

重要:组件只能在注册它的那个组件 template 内部使用;student 只在 school 里面注册,app 和 vm 中不能直接写<student></student>

三、两段代码易错点总结

  1. 组件data必须函数,不要写成对象data:{},复用组件数据会互相污染
  2. template 模板只能一个根 div,不能并列多个根标签
  3. 原生浏览器环境,组件标签必须成对<xxx></xxx>,不要自闭合<xxx/>
  4. 全局注册全部可用;局部注册,只在当前组件生效
  5. 嵌套:子组件写在父组件components,不是写在最外层 vm;谁要用,谁注册。

补充小区别

  • vm(new Vue):根 Vue 实例,唯一,负责挂载页面
  • 普通组件:不能直接挂载,必须被别的组件 /vm 调用

VueComponent 核心知识点

Vue.extend()返回的不是普通对象,是VueComponent 构造函数

  • vmnew Vue()得到,Vue 实例
  • vc:组件实例,new VueComponent()得到,Vue 内部自动帮我们 new,不用手动写

1. 关键要点

  1. const school = Vue.extend(options)school就是VueComponent 构造函数,不是实例。 页面写<school></school>,Vue 底层自动执行new school(),生成组件实例 vc。
  2. 每一次Vue.extend(),都会生成一个全新独立的 VueComponent 构造函数
const school = Vue.extend({...}) const hello = Vue.extend({...}) // school 和 hello 是两个完全不同的构造函数,互不干扰
  1. this 指向(高频考点)
  • 组件内 data /methods/computed /watch 里面的 this → vc(组件实例 VueComponent)
methods:{ showName(){ console.log(this) // vc 组件实例对象 } }
  • new Vue({})根实例里面 data/methods 中的 this →vm(Vue 实例)
  1. vm 和 vc 的关系
  • vc.__proto__ === VueComponent.prototype
  • VueComponent.prototype.__proto__ === Vue.prototype
  • 实例.proto→ 指向自己构造函数的.prototype
  • 构造函数.prototype→ 是实例的原型对象

笔试经常考:

Q:组件实例 vc 为什么可以调用this.$emit? A:vc 的原型链:vc.__proto__ → VueComponent.prototype.__proto__ → Vue.prototype$emit定义在 Vue.prototype 上,沿着原型链查找到。

Q:VueComponent 和 Vue 是什么关系? A:不是相等,是原型继承关系。

小总结

  1. ✅拿能力:继承 Vue 原型上所有实例方法,组件可以做事件通信
  2. ✅省代码:不需要复制一套 API
  3. ✅做隔离:组件和根实例区分开,组件不允许写 el
  4. ✅面试高频考点

通俗比喻

Vue.prototype好比一个工具箱,里面放着$emit$watch各种工具。

  • vm(根实例):直接拿着这个工具箱。
  • vc(组件):不直接拿工具箱,通过一根链子(原型链),可以访问工具箱里面全部工具。 但是 vc 自己不能做根 vm 的事情(不能写 el 挂载页面)。

例子普通 JS:

原型链:vc → VueComponent.prototype → Vue.prototype 所以组件实例 vc,可以直接使用 Vue 原型上的方法,比如$watch$emit等。

  1. 局部注册的子组件:谁要用,谁就在自己的components选项注册。 示例代码中:
  • test组件只在hello组件内部注册,所以只有hello的 template 中可以写<test></test>
  • #root容器、school 组件中直接写<test></test>会报错,没有注册。
<div id="root"> <school></school> <hello></hello> <!-- <test></test> 这里直接写会报错!vm没有注册test组件 --> </div>

6. 打印验证(打开控制台可以看)

console.log(school) // VueComponent构造函数 console.log(vm) // vm 根Vue实例

点击按钮,控制台打印的this就是 vc 组件实例。

7. 简写回顾

//完整写法 const school = Vue.extend({ template:'...', data(){return{} } }) //简写,省略Vue.extend,Vue底层会自动帮我们调用 const school = { template:'...', data(){return{} } }

8. vm 和 vc 对比表格

表格

vm(Vue 实例)vc(VueComponent 组件实例)
创建方式new Vue(options)Vue 内部自动new VueComponent()
el 配置✅可以写 el❌组件不能写 el
data对象 / 函数都可以必须是函数
thisvm 实例vc 组件实例
作用根实例,挂载容器复用组件

原型链理解:组件实例可以继承 Vue 原型上所有的属性和方法,所以 vc 也能调用$emit$on等。

易错坑

  1. 不要手动写new school(),Vue 解析组件标签自动帮你 new。
  2. 多次复用同一个组件标签,每一个标签都会生成独立 vc 实例,data 函数返回新对象,数据隔离。
  3. 子组件只对注册它的父组件生效,外部无法直接使用。

Vue 脚手架笔记整理

一、脚手架文件结构

├── node_modules # 项目所有依赖包,npm install自动生成,不要手动改 ├── public │ ├── favicon.ico # 浏览器页签小图标 │ └── index.html # 唯一主页面,整个Vue项目挂载在这里 ├── src # 写代码的源代码文件夹(我们主要操作这里) │ ├── assets # 静态资源:图片、css等 │ │ └── logo.png │ ├── components # 存放.vue组件(自定义组件放这里!) │ │ └── HelloWorld.vue │ ├── App.vue # 根组件,汇总所有其他组件 │ └── main.js # **项目入口文件**,程序从这里开始运行 ├── .gitignore # git忽略哪些文件不做版本管理 ├── babel.config.js # js语法转译配置(ES6转ES5兼容旧浏览器) ├── package.json # 项目配置:项目名字、版本、npm命令、依赖列表 ├── package‑lock.json # 锁定包版本,保证所有人安装版本一致,不要手动修改 └── README.md # 项目说明文档

✨重点:自定义组件建议放在src/components/文件夹导入路径示例:import Student from './components/Student.vue'你刚才报错就是路径写错,没有指向 components 文件夹。


二、Vue 两个版本区别

  1. vue.js(完整版)包含:Vue 核心功能 +模板解析器可以使用template:配置项写模板。
  2. vue.runtime.xxx.js(运行时版,脚手架默认用这个)只包含:Vue 核心功能,没有模板解析器
  • ❌不能写template配置项
  • ✅要用render(createElement)函数生成页面内容
// main.js脚手架默认写法 new Vue({ render: h => h(App) }).$mount('#app')

render 函数作用:代替模板解析器,把 App.vue 渲染到页面。

记忆口诀:完整版带解析器,运行版不带解析器,脚手架用运行版靠 render。


三、vue.config.js 配置文件

这个文件脚手架初始不会自动生成,需要自己在项目根目录手动新建。

  1. 查看脚手架全部默认配置(终端执行)
vue inspect > output.js

执行后项目根目录会生成output.js,里面是全部默认配置。

  1. 常用配置(课堂练习必用)
module.exports = { lintOnSave: false, //关闭eslint代码规范校验,消除一堆波浪警告 }

修改完必须:Ctrl+C停止服务,重新npm run serve才生效。

  1. 官方文档:https://cli.vuejs.org/zh

配套考点小结

  1. 整个 Vue 项目只有一个真正的 html 文件:public/index.html
  2. main.js 入口文件,创建 Vue 实例。
  3. App.vue 是根组件,所有组件都在它里面汇总。
  4. 组件放 components 文件夹,导入路径写对,否则报Module not found找不到模块。

ref 属性总结

作用

ref用来给DOM 元素或者组件实例打标识,之后通过this.$refs.xxx获取对应的对象。

两种使用场景

1. ref 写在普通 HTML 标签上

<h1 ref="title"></h1>
  • this.$refs.title得到原生 DOM 元素
  • 可以操作 DOM:获取 innerText、修改样式等

2. ref 写在组件标签上

<School ref="sch"/>
  • this.$refs.sch得到这个组件的实例对象(VueComponent)
  • 可以拿到组件内部的 data、调用组件的 methods 方法

你的代码示例拆解

showDom(){ alert(this.$refs.title); // <h1>...</h1> 原生DOM alert(this.$refs.sch); // School组件实例对象 }

⚠️注意点

  1. $refs只在挂载完成之后才有值,created()阶段拿不到,mounted()、点击事件里可以正常获取。
  2. $refs是对象,key 就是 ref 写的名字。
  3. ref不是响应式,不要拿来做数据绑定,只用于获取 DOM / 组件实例。
  4. 如果 v-for 循环里用 ref,this.$refs.xxx拿到的是数组。

记忆口诀

ref 打标记,$refs 来获取; 普通标签得 DOM,组件标签得实例。

props 笔记整理(考试背诵版)以props为主

props 配置项

  1. 功能:让子组件接收父组件传递过来的数据。
  2. 父组件传递数据
<!-- 传字符串 --> <Demo name="张三"/> <!-- 传数字、布尔、对象等,必须加 v-bind / : --> <Demo :age="18" :info="{a:1}"/>
  1. 子组件接收数据,三种写法

① 简单接收(只接收,不做校验)

props: ['name','age','sex']

② 接收 + 类型限制

props:{ name: String, age: Number, sex: String }

③ 接收 + 类型 + 是否必填 + 默认值(最重要)

props:{ name:{ type: String, // 限制数据类型 required: true, // 是否为必填项 true必填 default: '老王' // 默认值,父不传就用这个 } }

注意:requireddefault不要同时写;必填就不要给默认值。


⚠️重要备注(高频考点)

props 是只读!Vue 底层监视 props,子组件直接修改 props,控制台抛出警告,数据不会生效。

如果业务需要修改这份数据两种方案

  1. 方案一:复制到 data 副本(仅子组件内部使用,父组件数据不变)
data(){ return { myAge: this.age // 把props的age拷贝到data,之后修改myAge } }

局限:仅初始化拷贝一次;后续父组件更新 props,data 副本不会自动同步。

  1. 方案二:$emit 触发自定义事件(标准单向数据流,修改父源数据)子组件:
this.$emit('change-age', 20)

父组件监听事件修改自己的数据:

<StudentInfo :age="a" @change-age="a=$event"/>

易错点总结

  1. 传递非字符串,一定要加:,否则会当成字符串。
<Demo age=18 /> <!-- ❌age值是字符串"18" --> <Demo :age=18 /> <!-- ✅age值是数字18 -->
  1. default如果是对象 / 数组,必须写成函数返回,不能直接写对象字面量。
//对象类型默认值写法 info:{ type:Object, default(){ return {} } }
  1. props 优先级高于 data,template 可以直接使用 props 里的变量。

背诵短句

props 父传子,本身是只读; 简单数组接收,对象可以限制类型必填默认; 要改分两种,拷贝 data 改副本,或者 emit 通知父改源。

mixin 混入 笔记整理

1. 功能

多个组件重复共用的配置(data、methods、生命周期、computed 等)提取出来,做成混入对象,复用代码,不用每个组件重复写。

2. 使用方式

① 定义混入对象

新建mixin.js

export const myMixin = { data(){ return { msg:'混入的数据' } }, methods:{ show(){ alert('混入的方法') } }, mounted(){ console.log("混入的mounted") } }

② 局部混入(组件内使用,只对当前组件生效)

<script> import {myMixin} from './mixin' export default { name:'Demo', mixins:[myMixin], // 数组,可以写多个混入对象 // 组件自己配置 } </script>

③ 全局混入(main.js,所有组件全部生效)

import Vue from 'vue' import {myMixin} from './mixin' Vue.mixin(myMixin) //之后所有组件自动合并这个混入配置

3. ✨合并规则(考试重点)

  1. 生命周期钩子:全部执行,混入先执行,组件自身后执行

混入 mounted → 组件 mounted,两个都跑,不会覆盖。

  1. data、methods、computed:组件自身优先,会覆盖混入的同名属性
  • 如果混入和组件有同名 data/methods:组件自己的优先级更高,覆盖混入

示例: 混入:msg:'混入的数据'组件 data:msg:'组件自己的数据'最终页面显示:组件自己的数据

4. 特点 & 坑点

  1. 局部混入:只作用写了mixins:[xxx]的组件。
  2. 全局混入:所有组件,包括第三方组件都会生效,谨慎使用
  3. 可以传入多个混入对象mixins:[m1,m2,m3];多个混入之间,后面的会覆盖前面同名 data/methods。
  4. mixin 里面的 data 不是响应式共享,每个组件使用混入都会生成独立副本,互不干扰。

简短背诵版

mixin 抽公共配置,分为局部混入、全局混入; 生命周期钩子全都执行,混入先跑; data/methods 同名,组件自身优先级更高,覆盖混入。

对比

表格

局部混入全局混入
写法组件内mixins:[mixinObj]Vue.mixin(mixinObj)main.js 写
生效范围当前组件项目全部组件

小考点:mixins数组,可以引入多个混入对象。

Vue2 插件 (plugin) 笔记

1. 功能

用来增强 Vue,可以给 Vue 添加全局功能:全局过滤器、全局指令、全局混入、实例方法 / 属性。

2. 本质

插件是带有install方法的对象

const myPlugin = { install(Vue, options){ // 插件逻辑 } }
  • 第一个参数:Vue构造函数
  • 第二个参数options:使用者调用Vue.use(插件, 传入的配置)传过来的数据

3. 自定义插件完整写法

// my-plugin.js export default { install(Vue, options) { //1.全局过滤器 Vue.filter('myFilter', function(val){ return val.toUpperCase() }) //2.全局自定义指令 Vue.directive('focus',{ inserted(el){ el.focus() } }) //3.全局混入 Vue.mixin({ mounted(){ console.log('插件全局mixin') } }) //4.给Vue原型添加实例方法/属性,所有组件可以 this.$xxx 调用 Vue.prototype.$hello = function(){ alert('hello插件') } Vue.prototype.$test = 100 } }

4. 使用插件:Vue.use(插件, [配置参数]) 配置的参数可传递给插件

main.js引入并使用

import Vue from 'vue' import myPlugin from './my-plugin' // 使用插件,第二个参数传给install的options Vue.use(myPlugin, { name:'测试配置' }) new Vue({ el:'#app' })

⚠️重要:Vue.use()要写在new Vue()之前。

install 内部四种增强能力汇总

  1. Vue.filter()— 注册全局过滤器
  2. Vue.directive()— 注册全局指令
  3. Vue.mixin()— 设置全局混入
  4. Vue.prototype.$xxx— 添加实例方法 / 属性,组件内部this.$xxx访问

高频考点 & 坑

  1. 插件必须有install方法;没有 install 的对象不能作为插件。
  2. Vue.use(插件, 配置对象),配置对象会作为 install 的第二个参数。
  3. Vue.use()会自动缓存,同一个插件多次 use 只会执行一次 install
  4. 原型上挂载的方法,所有组件实例通过this.$xxx访问;不要和内置属性重名。

背诵短句

插件增强 Vue,本质带 install 的对象; install 第一个参数是 Vue 构造函数,第二个是配置 options; use 来启用,可以注册过滤器、指令、全局混入、原型方法; use 写在 new Vue 之前。

对比区分

表格

mixin 混入plugin 插件
作用复用组件配置 (data/methods/ 生命周期)全局增强 Vue 能力
局部使用mixins:[xxx]无局部,只能 Vue.use 全局注册
全局Vue.mixin()Vue.use(plugin)

插件内部可以调用Vue.mixin()实现全局混入。

scoped 样式笔记

1. 作用

<style scoped>让样式只作用于当前组件,防止不同组件之间样式冲突(样式污染)

2. 写法

<style scoped> .box { color: red; } </style>

3. 底层原理

Vue 给当前组件所有 DOM 标签自动生成唯一data‑v‑xxx属性,同时编译 css,给每一条选择器加上这个属性筛选。

模板:

<div class="box" data‑v‑7ba2ac34></div>

编译后 css:

.box[data‑v‑7ba2ac34] { color:red; }

样式只会匹配带这个data‑v‑xxx属性的元素,别的组件没有该属性,不会被影响。

4. 坑点(考试常考)

  1. scoped 样式,无法修改子组件内部的 DOM 元素子组件模板的标签会带自己的data‑v属性,父组件 scoped 的选择器带父的data‑v,匹配不到子组件内部元素。
  2. 深度选择器>>>//deep/,用来穿透 scoped,修改子组件内部样式
/* vue2 */ .box >>> .child-inner{ color:blue; } /* 或者 */ .box /deep/ .child-inner{ color:blue; }
  1. 去掉scoped,样式变成全局样式,整个项目所有组件都会生效,容易类名冲突。
  2. 一个组件可以写多个 style 标签,可以一部分 scoped 局部,一部分全局:
<style scoped> /* 局部 */ </style> <style> /* 全局,无scoped */ </style>

背诵短句

scoped 实现组件样式局部生效,防止样式冲突; 原理添加唯一data‑v‑xxx属性; scoped 不能直接改子组件内部样式,需要深度选择器/deep/穿透。

对比

表格

写法生效范围
<style scoped>仅当前组件局部
<style>全局,所有组件

考点问答题:为什么加 scoped 就不会样式冲突? 答:Vue 编译时给组件 DOM 添加唯一data‑v‑xxx属性,css 选择器自动附加该属性,样式只匹配本组件 DOM。

CSS 和 Less 的区别

CSS:原生层叠样式表,浏览器直接识别。Less:CSS 预处理器,不是原生 CSS,浏览器不认识,必须编译转换成普通 CSS 才能运行。

对比表

表格

对比原生 CSSLess(预处理器)
本质浏览器可直接解析的样式语言CSS 的增强工具,最终编译输出 CSS
变量❌没有变量,写死颜色、尺寸✅支持变量@color:red;,统一管理
嵌套❌只能平铺写选择器✅支持嵌套,贴合 HTML 结构,代码简洁
运算❌不能计算✅支持加减乘除width:100px + 20px
样式复用❌复制粘贴重复代码✅Less‑mixin,复用一套样式片段
导入@import "a.css"@import "a.less",可以引入 less 文件
浏览器直接运行不能直接运行,需要编译成 CSS

示例对比

✅原生 CSS
.box { color:#f00; } .box .item { font‑size:16px; } .box:hover { background:#eee; }
✅Less 写法
@red: #f00; .box{ color:@red; .item{ font‑size:16px; } &:hover{ background:#eee; } }

打包的时候,less 会被编译转换成上面那份普通 CSS 交给浏览器。

在 Vue 中使用

<!-- 普通css --> <style scoped> .box{} </style> <!-- less,必须加 lang="less" --> <style lang="less" scoped> @c:red; .box{ color:@c; } </style>

安装依赖:npm i less less‑loader@7 -D

Less 新增四大能力(CSS 没有)

  1. 变量@xxx,统一管理颜色、尺寸
  2. 嵌套,减少重复写父选择器;&代表自身
  3. 运算,尺寸、颜色可以计算
  4. mixin 样式混入,复用一堆 css 属性

关键点

  1. Less不能替代 CSS,只是写 CSS 的工具;最终产物依旧是 CSS。
  2. 浏览器只认识 CSS,不识别@变量、嵌套这些 less 语法。
  3. 写 less 只是开发阶段方便,打包自动翻译成 css。

记忆口诀

CSS 浏览器直接跑; Less 是预处理器,写得爽,编译变 CSS; 新增变量、嵌套、运算、样式 mixin。

注意区分两个 mixin:

  • Vue 的 mixin:JS 逻辑复用(script)
  • Less 的 mixin:样式代码复用(style)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/19 10:35:42

Polars数据处理核心:行列选择与数据转换实战指南

1. 从“选择”到“转换”&#xff1a;Polars数据处理的核心两步 如果你从Pandas转向Polars&#xff0c;或者刚开始用Polars处理数据&#xff0c;最先要搞明白的不是它的语法有多快&#xff0c;而是怎么把数据“拿过来”和“变过去”。这说的就是 行列选择 和 数据转换 。很…

作者头像 李华
网站建设 2026/8/19 10:35:27

如何一键给安卓APK应用加卡密验证?Ars验证系统防破解授权保护方案

在安卓软件防破解领域&#xff0c;将卡密验证模块注入到目标 APK 中&#xff0c;是一种常见的防破解保护手段。通过 APK 注入技术&#xff0c;可以把卡密验证逻辑嵌入到目标应用内部&#xff0c;使应用启动时先弹出卡密验证界面&#xff0c;未通过验证则无法进入主功能。Ars验证…

作者头像 李华
网站建设 2026/8/19 10:34:05

受够了散乱的文件?用OpenKM文档管理系统搭建统一文档平台

受够了散乱的文件&#xff1f;用OpenKM文档管理系统搭建统一文档平台 【免费下载链接】document-management-system OpenKM is a Open Source Document Management System 项目地址: https://gitcode.com/gh_mirrors/do/document-management-system 如果你的团队还在靠Q…

作者头像 李华
网站建设 2026/8/19 10:28:49

SAP Gateway 后端错误响应控制,如何让 OData 错误既能给用户看,也能让开发人员快速定位

在 SAP Gateway 项目里,最令人头疼的接口问题往往并不是 OData 请求直接返回 500 Internal Server Error,而是接口明明已经发现了业务问题,却不知道应该把什么信息返回给前端。 销售订单保存失败了,后台 BAPI 返回十几条消息。到底哪一条应该显示在 SAP Fiori 页面顶部,哪…

作者头像 李华