Vue2.x 基本认识二:使用 Vue CLI 的 Vue 项目
注意
- Vue CLI(手脚架)创建项目需要安装Node.js,没安装的看这里。
- 使用 Vue CLI 创建与运行项目,看这里。
- Vue CLI 创建的项目文件夹和文件说明,看这里。
- 此处使用手脚架版本为:@vue/cli 5.0.8
- 创建的项目中有 vue.config.js 文件,在内部添加配置,防止出现要求组件名称必须是多个单词的情况。
不配置会出现错误信息:Component name "XXX" should always be multi-word
具体配置方式:
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, lintOnSave: false /*关闭语法检查*/ })
单文件组件
定义和引入
<template> <div> <!-- 两种组件标签编写方式 --> <School></School> <Student/> </div> </template> <script> // 引入其他组件(组件后面的扩展名用不用都无所谓) import School from "./components/School.vue"; import Student from "./components/Student"; // 默认暴露简写+组件定义简写 export default { name: 'App', components: { School, Student } } </script>
render 函数
render 函数返回的是虚拟 DOM,与 data 配置项平级。
render 函数被 Vue 用到的是 createElement 参数
关于不同版本的 Vue 说明
1. vue.js 与 vue.runtime.xx.js 的区别:
(1)vue.js 是完整版的 Vue,包含核心功能和模板解析器。
(2)vue.runtime.xxx.js 是运行版的 Vue,值包含:核心功能,没模板解析器。
2. 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。
ref 属性
作用一:该属性在传统 HTML 标签上使用,能让 Vue 能操作 DOM 。
使用方法:
<!-- 在需要操作的 DOM 元素上加上 ref 属性 --> <div ref="headContent"></div> <!-- 在需要操作的地方这样使用,注意下面的 this 是指 vm 或 组件对象实例 --> this.$refs.headContent
作用二(重点):该属性在组件标签上使用,能拿到对应组件的对象实例。
// ref 使用方式 <button @click="getDom">点击调用getDom()</button> <div ref="headContent"></div> <School ref="sch"></School> // 操作被 ref 属性标记的标签,注意下面的 this 是指 vm 或 组件对象实例 this.$refs.headContent // 会得到一个真实 DOM 元素 this.$refs.sch // 会得到 School 组件的对象实例
props 配置项
功能:该配置用于接收父组件传给子组件的参数
注意:
接收到的参数所在位置:跟 data 配置项中的属性一样,在组件对象实例上。使用方式与 data 配置项中的属性一致。
关于参数优先级:子组件接收到的参数,比子组件从 data 配置项中拿到的属性优先级高。如果接收到的参数和 data 中存在同名属性,那么接收到的参数优先使用。
参数修改问题:子组件接收到的参数不能直接修改。想要修改,可以先在 data 配置项中定义一个属性,将接收到的参数值赋给定义的属性,然后修改自定义的属性值即可。另外,如果接收到的参数是一个对象,那么修改对象里面的属性值是被允许的。也就是说 props 检测的比较浅层,跟 Vue 的深度监测不同,props 只管第一层不能修改。
使用 v-bind 绑定参数传参:相当于将一个表达式作为参数传给子组件,这种方式,可以传各种类型参数,数值,对象,数组,函数等都可以。
简单接收(父传子)
<!-- 这里是父组件的 template --> <template> <div> <!-- 引入子组件:注意age属性的两种写法,接收到的参数是不同的类型,加了冒号相当于将一个表达式作为参数传给子组件,这种方式,可以穿各种类型参数,数值,对象,数组等都可以 --> <Student name="白修远" sex="男" age="18" /> <Student name="沈宜修" sex="女" :age="16" /> </div> </template> <!-- 下面都是子组件的内容 --> <template> <div> <h1>{{ msg }}</h1> <h3>学生姓名:{{ name }}</h3> <h3>学生性别:{{ sex }}</h3> <h3>学生年龄:{{ age + 1 }}</h3> </div> </template> <script> export default { name: 'Student', data() { return { msg: "欢迎来到大雪山" } }, props: ['name', 'sex', 'age'] // 简单声明接收 } </script>
页面效果:
接收参数(父传子):限制参数类型
props: {
name: String,
sex: String,
age: Number
}
接收参数(父传子):限制参数类型、设置默认值、限制必填性
props: { name: { type: String, require: true }, sex: { type: String, default: '男' }, age: Number }
注意:参数类型存在限制时,如果传错了会有提示,但不影响模板解析
接收函数(子传父)
传参:这种传参方式与简单传参的传参和接收方式一致。就是在父组件中定义一个操作自己属性的函数,将函数作为参数通过 props 的方式传给子组件。这个函数有参数也不用管,将函数名作为要穿参数的属性值即可。
注意:传的时候属性前面加 v-bind 或它的简写形式,将函数作为表达式传给子组件,否则就是只传了个普通字符串给子组件;另外,传给子组件的函数名不能和子组件中的函数冲突。
使用:子组件通过 props 配置项接收到这个函数,就可以直接使用了,而这个函数操作的又是父组件的数据,因此可以完成传值。在下面 组件的自定义事件 章节中有案例。
mixins(混合或叫混入)配置项
功能:可以把共用的配置项 data、methods 等,提取成一个混入对象,在需要使用的组件当中引入即可。
注意:
混入是增量的。例如组件当中存在 methods 配置项,已有的函数不会被混入对象中 methods 配置项中的函数替换,而是合并,全部提供给组件使用。
混入时,如果存在相同的属性或者函数,则以组件当中的为主。其他生命周期钩子函数,会同时使用,先执行混入的生命周期钩子函数,在执行组件当中的生命周期钩子函数。
定义混入对象 示例:创建一个 js 文件,内容如下
export const mixinData = { methods: { data() { return { x: 108 } } } } export const mixin1Methods = { methods: { showName() { alert(this.name) } } }
局部引入以及使用混入对象 示例:
<template> <div id="schoolContent"> <h3 @click="showName">学校名称:{{ name }}</h3> <h3>学校地址:{{ address }}</h3> </div> </template> <script> // 引入混入 import {mixinData, mixin1Methods} from '../mixin' export default { name: 'School', data() { return { name: "大雪山修仙学院", address: "昆仑" } }, // 使用混入 mixins: [mixinData, mixin1Methods] } </script>
全局引入及使用混入对象,示例:(main.js中)
// 全局引入混入 import {mixinData, mixin1Methods} from '../mixin' // 全局使用混入(这样,Vue 实例对象和所有组件实例对象都能使用下面添加的混入) Vue.mixin(mixinData) Vue.mixin(mixin1Methods)
插件
定义插件
创建一个 js 文件,名字随便,有意义即可,下面文件名:plugins.js
export default { // Vue 注意,参数是创建 Vue 实例的模板,不是 Vue实例 // x、y、z 是在引入插件时穿进来的,名称随便定义 install(Vue, x, y, z) { // 定义过滤器 // 定义指令 // 定义混入 // 给 Vue 原型上添加一个函数,vm 和 组件实例对象 都能使用 Vue.prototype.hello = ()=> { console.log('你好') } } }
引入和应用插件
在 main.js 文件当中
// 引入插件 import plugins from './plugins' // 引用插件 Vue.use(plugins, 1, 2, 3)
style 标签的属性
scoped 属性:控制样式作用域
使用:在子组件中,这个属性用在样式标签上:<style scoped>
效果:使用此属性的子组件样式只在组件 <template> 标签内生效,不会影响别的组件。
注意:如果在 父组件(类似App组件)中使用,那么父组件中的所有样式,还会影响到子组件。
lang 属性控制样式语言
使用:<style lang="less">,lang 属性的值使用 css、less 等,都是按开发需求来定。
如果要使用 less,注意添加 less 支持,Vue CLI 如果是 4 版本,安装 less 支持最好是5、6、7版本,如果手脚架是5,那么 less 支持可以安装 8、9(这里提到的版本都是大版本)
查看 Vue 项目中使用的 webpack 版本:node_modules\webpack\package.json
查看 webpack 所有版本命令:npm view webpack versions
查看 less-loader 所有版本:npm view less-loader versions
安装命令:npm i less-loader 或 npm i less-loader@[版本号],这里版本号可以不写详细版本,只写个大版本,这样默认会安装这个大版本中最新的版本。
组件拆分原则
根据功能点来拆分。每负责一个功能的模块,都可以拆分出来,作为一个组件。
例如:一个列表中,每个 item 都是可以增删改的,那么,这个列表可以拆成两个组件,一个用于遍历展示所有 item,一个就是 item 组件本身,二者是父子关系。
组件的自定义事件
作用:适用于子组件给父组件传参,父组件给子组件传函数
绑定自定义事件:两种方式
注意:下面是绑定自定义事件,如果要绑定原生的事件,例如 click 事件,在写完 @click 之后,需要加一个修饰符,也就是 @click.native,这样就会给子组件绑定一个点击事件,事件会绑定在子组件的根元素上
文件:App.vue
<template> <div id="app"> <h1 id="welcomeTitle">{{ msg }}</h1> <!-- 通过 props 的方式,将函数作为一个参数传给子组件,由子组件触发函数 --> <School :getSchoolNameFunc="getSchoolName" /> <!-- 方式一 通过指令语法 v-on 给子组件绑定一个自定义事件 getStudentNameEvent,该事件触发,就会回调 getStudentName 函数 子组件通过 $emit 函数触发事件,至于什么时候触发,由子组件控制 子组件不再需要像 props 传参那样定义配置项接收函数,然后触发,这是绑定在子组件对象实例上的一个事件,可以直接触发 --> <!-- <Student v-on:getStudentNameEvent="getStudentName" /> --> <!-- 方式二 通过 ref 属性,使 App 组件能拿到 Sutdent 组件的对象实例,然后通过 $on 绑定一个事件到 Student 组件对象实例上 --> <Student ref="student" /> <!-- 上面两种方式绑定的事件触发方法都一样,都是通过 $emit 函数 --> </div> </template> <script> // 引入其他组件(组件后面的扩展名用不用都无所谓) import School from "./components/School.vue"; import Student from "./components/Student"; // 默认暴露简写+组件定义简写 export default { name: 'App', components: {School,Student}, data() { return { msg: "欢迎来到大雪山" } }, methods: { getSchoolName(name) { console.log("App拿到了学校名称:" + name) }, getStudentName(name) { console.log("App拿到了学生名称:" + name) } }, mounted() { this.$refs.student.$on('getStudentNameEvent', this.getStudentName) } } </script>
自定义事件的触发($emit)和解绑($off)
文件:Student.vue
<template> <div id="studentContent"> <h3>学生姓名:{{ name }}</h3> <h3>学生性别:{{ sex }}</h3> <h3>学生年龄:{{ age + 1 }}</h3> <button @click="sendNameToApp">点击将学生姓名传给App组件</button> <button @click="unbind">点击解除绑定的自定义事件</button> </div> </template> <script> export default { name: 'Student', data() { return { name: "白修远", sex: "男", age: 18 } }, methods: { sendNameToApp() { /** * $emit(eventName, ...args) 函数是触发指定的事件,根据事件本身需要传参 */ this.$emit('getStudentNameEvent', this.name) }, unbind() { // 解除绑定的事件:事件绑定在谁身上,谁解绑 this.$off('getStudentNameEvent') // 解绑一个自定义事件 //this.$off(['getStudentNameEvent','eventNameXxx'...]) // 解绑多个自定义事件 this.$off() // 解绑所有自定义事件 } } } </script>
注意,调用实例销毁函数后,也会解除和销毁所有自定义事件的绑定。
文件:School.vue(这里主要是 props 传参)
<template> <div id="schoolContent"> <h3>学校名称:{{ name }}</h3> <h3>学校地址:{{ address }}</h3> <button @click="sendNameToApp">点击将学校名称传给App组件</button> </div> </template> <script> export default { name: 'School', props: ["getSchoolNameFunc"], data() { return { name: "大雪山修仙学院", address: "昆仑" } }, methods: { sendNameToApp() { this.getSchoolNameFunc(this.name) } } } </script>
全局事件总线(重要)
功能:实现任意组件之间通信。
思路:让一个组件 X 能让所有组件看见。A 组件给 X 组件一个自定义事件,回调函数肯定在 A 当中(上面组件自定义事件有说)。当 C 组件想给 A 组件传参时,让 C 组件触发 X 组件上 A 定义的自定义事件,并且传参,这样 A 组件就成功收到参数了。
注意:
- 哪个组件对象实例要传递参数,那么就在这个组件触发事件。
- 哪个组件要收到参数,那么就在这个组件里向全局事件总线绑定事件,并且定义回调函数。
- 在组件销毁前调用的钩子函数(beforeDestroy)中,解除对全局事件总线绑定的事件
定义方式
文件:main.js
const vm = new Vue({ render: h => h(App), beforeCreate() { Vue.prototype.$bus = this // 安装全局事件总线 } }).$mount("#root")
组件使用全局事件总线:绑定事件&解绑事件
文件:Student.vue
<template> <div id="studentContent"> <h3>学生姓名:{{ name }}</h3> <h3>学生性别:{{ sex }}</h3> <h3>学生年龄:{{ age + 1 }}</h3> <button @click="destroySelf">点击自杀</button> </div> </template> <script> export default { name: 'Student', data() { return { name: "白修远", sex: "男", age: 18 } }, methods: { selfIntroduction(schoolName, schoolAddress) { console.log('欢迎来到' + schoolAddress + ',在下', schoolName, this.name) }, destroySelf() { let cueWords = '[系统]你确定要自杀吗?死后将身消道陨,一切因果都将一笔勾销。' if (!confirm(cueWords)) return // 调用销毁方法,销毁当前组件对象实例 this.$destroy() } }, mounted() { // 在事件总线上面绑定一个事件:selfIntroductionEvent,回调函数是 methods 配置中的 selfIntroduction this.$bus.$on('selfIntroductionEvent', this.selfIntroduction) }, // 在销毁前,解除自己绑定在事件总线上面的事件 beforeDestroy() { this.$bus.$off('selfIntroductionEvent') } } </script>
组件使用全局事件总线:触发事件
文件:School.vue
<template> <div id="schoolContent"> <h3>学校名称:{{ name }}</h3> <h3>学校地址:{{ address }}</h3> <h5>[系统]此时,一位迷途少女来到学院,见对面之人,便向对方发出询问</h5> <button @click="inquiry">你好,请问你是?</button> </div> </template> <script> export default { name: 'School', data() { return { name: "风雪修仙学院", address: "昆仑-大雪山" } }, methods: { inquiry() { /** * 触发 Student 组件绑定在全局事件总线上的事件 * 因为事件绑定在 $bus 上面,所以有下面写法, * 千万别 this.$emit,this身上并没有这个事件,使用 $emit 去触发不会报错,但也没任何提示 */ this.$bus.$emit('selfIntroductionEvent', this.name, this.address) } } } </script>
消息发布与订阅
功能:能够实现组件之间的任意通信
案例使用的库:pubsub-js,安装方式:npm i pubsub-js
说明:使用什么库都无所谓,消息发布与订阅是一种理念。
消息发布
文件:School.vue
<script> // 引入 pubsub import pubsub from 'pubsub-js' export default { name: 'School', data() { return { name: "大雪山修仙学院", address: "昆仑" } }, methods: { // 该函数被调用时,发布消息 publishFairylandMsg() { // 发布消息 let data = { name: this.name, address: this.address } pubsub.publish('fairylandMsg', data) } } } </script>
消息订阅与取消订阅
文件:Student.vue
<script> // 引入 pubsub import pubsub from 'pubsub-js' export default { name: 'Student', data() { return { name: "白修远", sex: "男", age: 18 } }, methods: { /** * 写法三的回调函数:(该函数 Vue 是管理的,所以 this 是当前组件对象实例) * 第一个参数如果不需要,可以用下划线占位 */ subscribeFairylandMsg(_, data) { console.log('写法三收到消息:', data) } }, mounted() { // 订阅消息:写法一(这种写法回调函数内 this 是 undefined) // this.pubId = pubsub.subscribe('fairylandMsg', function(msgName, data){ // console.log('写法一收到', msgName, '渠道的消息:', data) // }) // 订阅消息:写法二(这种写法回调函数内 this 是当前组件对象实例,因为箭头函数 this 指向会向外层找) // this.pubId = pubsub.subscribe('fairylandMsg', (msgName, data) => { // console.log('写法二收到', msgName, '渠道的消息:', data) // }) // 订阅消息:写法三 this.pubId = pubsub.subscribe('fairylandMsg', this.subscribeFairylandMsg) }, beforeDestroy() { // 对象实例被销毁前 取消消息订阅 pubsub.unsubscribe(this.pubId) } } </script>
$nextTick(重要)
功能:这个函数可以让指定的代码在 Vue 将模板解析 且 DOM 更新完毕之后再执行。
场景:在一个函数中,某个 data 配置项里面的属性值发生改变时,Vue 不会立即解析模板,而是等函数执行完毕之后,才根据所有变动的结果统一的去解析模板。简而言之,不是一个属性值变了就立即解析模板的。此时如果去操作 DOM,很可能得不到想要的结果。
注意:下面的 this 是 Vue 的对象实例 或者是 组件对象实例。
this.$nextTick(function(){ // 使某个 input 框获取焦点 this.$refs.xxx.focus(); })
过度与动画
<template> <div> <button @click="isShow = !isShow">点击显示|隐藏</button> <!-- 1. transition 标签如果使用了 name 属性,那么下面样式中进入和离开样式不在是“v-”,而是name属性值+“-” 例如:transition 有 name="transtest",那么下面就 “transtest-”。 指定 name 属性可以用于控制多个元素使用不同的动画效果。 2. transition 标签中,只能有一个根节点。即 id="testDiv" 的 div 元素不能有同级其他元素。 想要实现多个元素用同样的过度效果,需要使用 transition-group 标签,每个元素都要指定不同的 key 值。 3.集成 animate.css(官网地址:https://animate.style/) 后,transition、transition-group 标签需要用到的两个属性: enter-active-class="" leave-active-class="" 这两个属性的值在 animate.css 官网右侧复制即可。 使用第三方库后,不需要自己写动画过度样式了(也就是style标签中的一些类不需要使用了) --> <transition appear> <div class="testDiv" v-show="isShow">A</div> </transition> <transition-group> <div class="testDiv" v-show="!isShow" key="1">B</div> <div class="testDiv" v-show="isShow" key="2">C</div> </transition-group> </div> </template> <script> export default { name:'AnimationTest', data() { return {isShow:true} } } </script> <style scoped> /* 进入的起点 */ .v-enter {} /* 进入过程中 */ .v-enter-active {animation: movetest 2s;} /* 进入的终点 */ .v-enter-to {} /* 离开的起点 */ .v-leave {} /* 离开过程中 */ .v-leave-active {animation: movetest 2s reverse;} /* 离开的终点 */ .v-leave-to {} @keyframes movetest { from { transform: translateX(-100%) } to { transform: translateX(0) } } .testDiv { width: 50px; height: 50px; background-color: rgb(174, 200, 59); } </style>
使用 axios 发送请求
在项目中安装 axios 命令:npm i axios
且不能灵活的控制请求是否走代理
代理配置方式
在 vue.config.js 文件当中
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, lintOnSave: false, /*关闭语法检查*/ // 开启代理服务器方式一:(此方式开启代理只能配置一个地址) // devServer: { // proxy: 'http://localhost:5000' // 需要代理的地址 // }, // 开启代理服务器方式二 devServer: { proxy: { '/api': { // 请求前缀,用于配置 axios 请求地址中端口号之后的内容 target: 'http://localhost:5000', pathRewrite: {'^/api':''} // 路径重写,替换请求地址中指定的字符串。这里将 /api 字符串替换为空字符串 // ws: true, // 默认是true,用于支持 websocket // changeOrigin: true // 默认是true,react中默认是false,用于控制请求头中的 host 值 }, '/api2': { // 请求前缀,用于配置 axios 请求地址中端口号之后的内容 target: 'http://localhost:5001', pathRewrite: {'^/api2':''} } } } })
使用 vue-resource 插件发送请求
功能:发送请求。类似 axios。
安装:npm i vue-resource
说明:该插件也是对 xhr 的封装,在 Vue1.x 中用的特别多。
引入插件
main.js 文件中
// 引入 vue-resource 插件 import vueResource from 'vue-resource' // 使用 vue-resource 插件 Vue.use(vueResource)
使用插件
除了调用 get 函数前面写法不同,返回结果与 axios 完全一致。
this.$http.get('http://localhost:8080/api/students').then( response => { console.log('请求成功', response.data) }, error => { console.log('请求失败', error.message) } )
使用代理方式
<script> // 引入 axios import axios from 'axios' export default { name: 'App', data() { return { msg: "欢迎来到昆仑-大雪山" } }, methods: { getStudentMsg() { /** * 后端服务接口地址(目标地址):http://localhost:5000/students * 方式一:这种代理方式需要修改目标地址中的端口号与本机(前端服务)端口同步。假设本服务启动端口为:8080 * 也就是修改为:http://localhost:8080/students * 注意,方式一 devServer 配置开启的代理,只有根路径(public)下没有的资源,才走代理 * 否则,下面会返回根路径中的资源 * 方式二:这种代理方式需要修改目标地址中的端口号与本机(前端服务)端口同步,且在端口号后面加了请求前缀 * 目标代理地址是 http://localhost:5000/students * 代理后请求地址 http://localhost:8080/api/students * 注意:两种代理方式端口号以后的内容,均不能和前端服务跟路径(public 目录)中的资源同步,否则请求不到后端。 * 以下面的请求地址为例,如果在 public 目录下存在 api 目录,且当中存在一个叫 students 的文件,那么在发起 * 求情后,返回的就是前端服务中 students 文件中的内容,而不是通过代理请求到后端接口拿想要的数据。 */ axios.get('http://localhost:8080/api/students').then( response => { console.log('请求成功', response.data) }, error => { console.log('请求失败', error.message) } ) } } } </script>
注:记录一个 github 提供的公共可用的获取用户信息的接口:https://api.github.com/search/users?q=xxx
插槽
默认插槽
默认插槽定义
<template> <div id="schoolContent"> <h3>学校名称:{{ name }}</h3> <h3>学校地址:{{ address }}</h3> <!-- 定义一个插槽(告诉 Vue 这往这里填充内容) --> <slot>标签内可以写默认值,如果组件使用者不填充,就展示这里的内容</slot> </div> </template>
默认插槽填充
注意,在下面组件标签体当中编写的内容,都会填充到组件当中定义的默认插槽位置,也就是说,可以同时写多个标签填充进去,下面案例只是写一个作为示范。
<template> <div id="app"> <h1 id="welcomeTitle">{{ msg }}</h1> <School> <!-- 向 School 组件定义的默认插槽填充的内容 --> <img src="xxx"/> </School> <Student/> </div> </template>
具名插槽
具名插槽定义
<template> <div id="schoolContent"> <h3>学校名称:{{ name }}</h3> <h3>学校地址:{{ address }}</h3> <!-- 定义具名插槽 --> <slot name="center">标签内可以写默认值,如果组件使用者不填充,就展示这里的内容</slot> <slot name="footer">标签内可以写默认值,如果组件使用者不填充,就展示这里的内容</slot> </div> </template>
具名插槽填充
<template> <div id="app"> <h1 id="welcomeTitle">{{ msg }}</h1> <School> <!-- 向具名插槽填充内容:填充的目标就是 name 属性值与下列标签中 slot 属性值相同的插槽 --> <h1 slot="center">向center插槽填充</h1> <h1 slot="center">向center插槽填充,多填充是追加的,不会覆盖前面填充的内容</h1> <!-- 多个元素同时向同一个插槽填充时 可以使用 <template> 标签,该标签既可以使用上面的 slot 属性指定具体插槽 也可以使用 Vue 2.6 提出的新写法,如下 --> <template v-slot:footer> <h1>向footer插槽填充</h1> <div>向footer插槽填充</div> </template> </School> <Student/> </div> </template>
作用域插槽
作用域插槽和尚明两种插槽在定义和填充上没有区别,只是在组件定义插槽的时候,在 <slot> 标签上自定义属性,通过 v-bind 的方式绑定插槽上面的属性。此时,插槽填充者就能直接在填充时使用该属性。
作用域插槽定义
<template> <div id="schoolContent"> <h3>学校名称:{{ name }}</h3> <h3>学校地址:{{ address }}</h3> <!-- 作用域插槽演示 --> <slot :name="name">这是默认插槽,具名插槽在搭配作用域概念是一样的,就不重复写了</slot> </div> </template>
作用域插槽填充
<template> <!-- 这个是App组件的标签,不要和下面 template 标签弄混了--> <div id="app"> <h1 id="welcomeTitle">{{ msg }}</h1> <School> <!-- 填充作用域插槽 作用域插槽必须使用 <template> 标签 标签内的 scope 属性指定的 params 对象可以接收到插槽传递过来的所有参数 (scope 属性可以用新的属性代替 slot-scope) 参数可以是某个属性,或者对象、数组,根据插槽定义时传递的参数来定 作用域插槽也是能指定 name 属性的,与上面具名插槽使用方式一致 --> <template scope="params"> <h1>{{ params.name }}</h1> </template> </School> <Student/> </div> </template>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律