Vue详细介绍及使用(组件)

您所在的位置:网站首页 vue类组件 Vue详细介绍及使用(组件)

Vue详细介绍及使用(组件)

2024-01-14 23:31| 来源: 网络整理| 查看: 265

                           Vue详细介绍及使用 一、Vue组件概念 1、基本的概念

    为什么需要组件化?在实际开发中,我们经常也会封装很多公共方法,达到复用的目的,也便于维护。对于前端也是一样,那么什么是组件?

    官方定义:组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

    组件机制的设计,可以让开发者把一个复杂的应用分割成一个个功能独立组件,降低开发的难度的同时,也提供了极好的复用性和可维护性。组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。组件化和模块化的视角不同:

模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用。

    可复用组件,高内聚、低耦合。Vue中提供了少量的内置组件(keep-alive、component、transition、transition-group等),但可以自定义组件。Vue API中,提供了Vue.extend和Vue.component两个全局方法创建/注册组件,还有一个实例选项components,用来注册局部组件。  

2、学习前准备 2.1、导入项目

    准备好开发工具Visual Studio Code,导入之前生成的项目案例。

项目目录:

目录/文件 说明 build 项目构建(webpack)相关代码 config 配置目录,包括端口号等。我们初学可以使用默认的。 node_modules npm 加载的项目依赖模块(根据package.json安装时候生成的的依赖安装包) src 这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件: assets 脚手架自动会放入一个图片在里面作为初始页面的logo。平常我们使用的时候会在里面建立js,css,img,fonts等文件夹,作为静态资源调用 components 用来存放组件,合理地使用组件可以高效地实现复用等功能,从而更好地开发项目。 router 路由相关的内容。该文件夹下有一个叫index.js文件,用于实现页面的路由跳转 main.js 入口文件,主要作用是初始化vue实例并使用需要的插件,小型项目省略router时可放在该处 App.vue 主组件,可通过使用开放入口让其他的页面组件得以显示。也可以直接将组件写这里,而不使用 components 目录。 static 静态资源目录,如图片、字体等。 .gitkeep git配置。 .babelrc es6解析的一个配置 .editorconfig 编辑器的配置文件 .eslintignore 忽略eslint语法规范检查配置文件 .eslintrc.js eslint(代码格式化检查工具)的配置文件,开启以后要严格遵照它规定的格式进行开发 .gitignore 忽略git提交的一个文件,配置之后提交时将不会加载忽略的文件 .postcssrc.js 文件是postcss-loader包的一个配置 index.html 首页入口文件,经过编译之后的代码将插入到这来。 package.lock.json 锁定安装时的包的版本号,并且需要上传到git,以保证其他人在npm install时大家的依赖能保证一致 package.json 项目配置文件。需要哪些npm包来参与到项目中来,npm install命令根据这个配置文件增减来管理本地的安装包。 README.md 项目的说明文档,markdown 格式 2.2、运行项目

    运行命令npm run dev启动项目(npm run 其实执行了package.json中的script脚本)。更多说明参考:https://blog.csdn.net/xiaoxianer321/article/details/114009647

源码:

webpack-将各项前端代码/资源打包编译成.js、.css、.png等浏览器可以加载的资源。

2.3、Visual Studio Code 插件使用

    在使用过程中经常出现编写不符合eslint规范,空格,缩进,各种括号,导致启动报错,真是头疼。

2.3.1、方式一:安装插件ESLint

然后File(文件)->Preferences(首选项)->settings(设置)

编辑settings.json文件将文件替换为下面的选项,就可以保存时自动格式化。

{ // vscode默认启用了根据文件类型自动设置tabsize的选项 "editor.detectIndentation": false, // 重新设定tabsize "editor.tabSize": 2, // #每次保存的时候自动格式化 "editor.formatOnSave": true, // #让prettier使用eslint的代码格式进行校验 "prettier.eslintIntegration": true, // #去掉代码结尾的分号 "prettier.semi": false, // #使用单引号替代双引号 "prettier.singleQuote": true, // #让函数(名)和后面的括号之间加个空格 "javascript.format.insertSpaceBeforeFunctionParenthesis": true, // #这个按用户自身习惯选择 "vetur.format.defaultFormatter.html": "js-beautify-html", // #让vue中的js按编辑器自带的ts格式进行格式化 "vetur.format.defaultFormatter.js": "vscode-typescript", "vetur.format.defaultFormatterOptions": { "js-beautify-html": { "wrap_attributes": "force-aligned" // #vue组件中html代码格式化样式 } }, // 格式化stylus, 需安装Manta's Stylus Supremacy插件 "stylusSupremacy.insertColons": false, // 是否插入冒号 "stylusSupremacy.insertSemicolons": false, // 是否插入分好 "stylusSupremacy.insertBraces": false, // 是否插入大括号 "stylusSupremacy.insertNewLineAroundImports": false, // import之后是否换行 "stylusSupremacy.insertNewLineAroundBlocks": false, // 两个选择器中是否换行 }

2.3.2、方式二:关闭校验规则

    找到build\webpack.base.conf.js这个文件:

    它是index.js中的一个配置:useEslint并将其值设置为: false,即关闭eslint规则校验。(并不推荐这么做)

二、组件的创建

    关于组件的创建源码分析,可以参考这篇文章:https://blog.csdn.net/xiaoxianer321/article/details/114340405

1、创建组件的构造器

    前面介绍过Vue.extend可以帮助我们对 Vue 实例进行扩展,扩展之后,就可以用此扩展对象创建新的 Vue 实例,Vue.extend是为了创建可复用的组件模板,更主要的是服务于Vue.component组件注册。

案例1:

vue-test-big var myVue = Vue.extend({ template: '{{ name }} - {{ age }} - {{ sex }}', data: function () { return { name: '小明', age: '19', sex: '男' }; } }); var extends1 = new myVue().$mount('#app'); var extends2 = new myVue().$mount('#app1');

案例效果:

    new  Vue(),  尽管在Vue官方文档上,在相当多的例子中使用到了创建Vue实例这个操作,实际上它的使用可能并没有你想象的那么频繁,在很多时候,它可能就只在挂载根实例的时候使用到。后面我们接触更多的是组件和路由的使用。

    在Vue 中定义一个组件模板,可以有很多种方式,下面只列出常见的几种:

1)字符串 // 注册 Vue.component('my-component', { template: 'A custom component!' }) 2)模板字面量 Vue.component('my-component', { template: `A custom component!` }) 3)x-template Vue.component('my-component', { template: '#checkbox-template' }) A custom component! 4)render 函数 Vue.component('my-component', { render(createElement){ return createElement('div','A custom component!') } }) 5)内联模板(inline-template 属性) 我是内联模板 6)单文件组件(.vue 文件) 1.1、单文件组件

    一般浏览器不能识别.vue的文件,所以需要vue-loader来加载.vue文件,所以需要基于webpack来开发。

    webpack:前端资源模块化加载器和打包工具,他能把各种资源当作模块进行加载,实际上就是通过不同的loader将这些资源加载打包然后输出打包文件。webpack是基于commonJs语法的。

    vue-loader:会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Vue.js 组件选项的对象。支持使用非默认语言,比如 CSS 预处理器,预编译的 HTML 模版语言,通过设置语言块的 lang 属性。

2、组件三要素

    传统前端中一个网页应用是由很多html文件组成,每个html文件又分为三部分:

   1)用于展示视图;

   2)用于和用户交互

   3)用于控制视图的样式。

    在vue中,每个单文件组件(.vue文件)也可分为三部分(例如:在App.vue中我们可以看到有:、、):

   1)用于展示视图:模板反映了数据和最终展现给用户的DOM之间的映射关系(注:一般只有一个根元素,vue初始化之后最终会得到一个vdom树,而树结构必须要求只有一个root节点)

   2)用于和用户交互;

   3)用于控制视图的样式。

1.1、< template >

    html中的template标签中(html5新增)的内容在页面中不会显示。但是在后台查看页面DOM结构存在template标签。

    在Vue中template模板是用于编写视图(DOM)的地方,一般只有一个根元素,通常根元素都是div。如果有多个根元素需要使用v-if、v-else、v-else-if设置成只显示其中一个根元素;(template标签不支持v-show指令,v-show="false"对template标签来说不起作用。)

1.2、< script >

    vue中的script脚本中包含两部分,导出和导入。

    历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。而ES6 在语言标准的层面上,它实现了模块功能,设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

    关于export和import命令可以参考这篇文章:https://blog.csdn.net/xiaoxianer321/article/details/113485872

1.3. < style>

    style里和传统的css差不多,不同的是支持了更多的语法,比如scss、less、stylus等,默认是css。

    CSS(层叠样式表):是一门非程序式语言,因为CSS没有变量、函数、SCOPE(作用域),需要书写大量看似没有逻辑的代码,不方便维护及扩展,不利于复用,尤其对于非前端开发工程师来讲,往往会因为缺少 CSS 编写经验而很难写出组织良好且易于维护的 CSS 代码。为了方便前端开发的工作量,出现了sass(sass技术的文件的后缀名有两种形式:.sass和.scss)和less,sass和less由于使用了类似JavaScript的方式去书写,所以必须要经过编译生成css,而html引用只能引用编译之后的css文件,虽然过程多了一层,但是毕竟sass/less在书写的时候就方便很多。

3、注册组件及使用

    在Vue中使用组件,可能需要用到注册组件,它提供了全局注册和局部注册两种方式。

3.1、全局注册组件Vue.component

    在全局api中有个Vue.component方法,提供了三种创建全局组件的方法,还有一种私有组件。

   Vue.component( id, [definition] )

参数:

{string} id{Function | Object} [definition]

用法:注册或获取全局组件。注册还会自动使用给定的 id 设置组件的名称

// 注册组件,传入一个扩展过的构造器 Vue.component('my-component', Vue.extend({ /* ... */ })) // 注册组件,传入一个选项对象 (自动调用 Vue.extend) Vue.component('my-component', { /* ... */ }) // 获取注册的组件 (始终返回构造器) var MyComponent = Vue.component('my-component')

案例:

    首先我们在main.js中加入我们要注册的组件,然后在App.vue中直接。

main.js 

// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' let head = Vue.extend({ template: '

This is a head component!

' }) Vue.component('tab-home', head) Vue.component('tab-new', { template: 'This is a News component' }) Vue.component('tab-foot', { template: 'This is a Foot component' }) /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '' })

App.vue 

案例效果:

3.2、局部注册组件

    通过某个Vue实例/组件的实例选项 components 注册,使用该选项注册的组件被称为局部注册。继续使用之前的案例,我们在加一个广告组件。我们将HelloWorld.vue中的内容重写一下,然后在APP.vue中使用。

HelloWorld.vue 

This is a advertisement component!

export default { name: 'HelloWorld', components: { 'my-component': { template: '#gg' } } }

App.vue

export default { name: 'App' } #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; }

案例效果:

 

三、组件间的通信

    一个简单的网页,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件,形成了类似的组件树结构,引用官网一张图:

    组件与组件之间的嵌套使用避免不了数据之间的传递。那么Vue中组件的数据是如何传递的呢?组件间数据传递不同于Vue全局的数据传递,组件实例的数据之间是孤立的,不能在子组件的模板内直接引用父组件的数据。如果要把数据从父组件传递到子组件,就需要使用props属性。在Vue中,父子组件的关系可以总结为:prop向下传递,事件向上传递。父组件通过prop给子组件下发数据,子组件通过事件给父组件发送消息。所以我们也会经常遇到组件之间需要传递数据的时候,大致分为四种情况:

父组件向子组件传递数据,通过 props 传递数据。子组件向父组件传递数据,通过 events(自定义事件-回调参数) 传递数据。两个同级组件(兄弟组件)之间传递数据,通过 EventBus (事件总线-只适用于极小的项目)、Vuex(官方推荐)传递数据。其他方式通信-处理边界情况:    1)$parent:父实例,如果当前实例有的话。通过访问父实例也能进行数据之间的交互,但极少情况下会直接修改父组件中的数据。    2)$root:当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。    3)$children:当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。    4)$ref:一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。访问子组件实例或子元素    5)provide / inject。主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。并且这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

1、父组件向子组件传递数据 1.1、通过 Prop 传递数据

    通过 Prop向子组件传递数据,父子组件之间的数据传递相当于自上而下的下水管子,只能从上往下流,不能逆流。这也正是 Vue 的设计理念之单向数据流(当父组件的属性变化时,将传给子组件,但是反过来不会)。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。

示例:

1)我们先定义好一个父组件(Parent.vue)和一个子组件(Child.vue)

2)Child.vue:我们需要使用父组件的数据定义在props中:props: ['myName', 'myAge']

    HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符,所以在模板中不能直接使用camelCase (驼峰命名法) 的 prop (myName,myAge),需要使用其等价的 kebab-case (短横线分隔命名) 命名。

子组件child数据 姓名: 您输入的姓名:{{ myName }} 年龄: 您输入的年龄:{{ myAge }} export default { props: ['myName', 'myAge'] } h3 { font-size: 24px; font-weight: 400; margin-top: 0; margin-bottom: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; padding: 0 20px; text-align: center; color: #fff; } ul { margin: 10px; padding: 0; list-style: none outside none; border: 1px solid #ccc; } input { padding: 5px 10px; border-radius: 3px; border: 1px solid #ccc; margin: 10px; height: 30px; } .child { background: #bd6ea2; padding: 10px; border-radius: 5px; color: #fff; margin: 0 5px; }

3) Parent.vue:在父组件中导入子组件,并引用子组件

父组件Parent数据 姓名: 您输入的姓名:{{ name }} 年龄: 您输入的年龄:{{ age }} import Child from './Child.vue' export default { data () { // data必须是一个函数,如果data不是一个函数,则无法达到每个组件数据都是独立的对象,这个受到javascript的本质影响,如果对象无法独立,则无法做到组件复用。 return { name: 'father', age: '28' } }, components: { 'my-child': Child } } h3 { font-size: 24px; font-weight: 400; margin-top: 0; margin-bottom: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; padding: 0 20px; text-align: center; color: #fff; } ul { margin: 10px; padding: 0; list-style: none outside none; border: 1px solid #ccc; } input { padding: 5px 10px; border-radius: 3px; border: 1px solid #ccc; margin: 10px; height: 30px; } .parent { background: #6882b8; padding: 10px; border-radius: 5px; color: #fff; margin: 0 5px; }

4)在main.js中注册父组件

// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import Parent from '@/components/props/Parent' Vue.component('my-parent', Parent) /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '' })

 5)在App.vue中使用父组件

export default { name: 'App' } #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; background-color: #f8f4f4; }

示例效果:当父组件的属性变化时,将传导给子组件,但是不会反过来。修改子组件的 prop 值,是不会传回给父组件去更新视图的。

    通过props传递给子组件的myName、myAge,不能在子组件内部修改props中的值。这样的操作破坏了单向数据流的设想,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。但是如果prop改成对象类型,子组件直接修改数据,不会引起警告(因为当参数是对象的时候,传给子组件的应该是类似于指针的一个东西,指向内存中的一个数据空间,而子组件通过 ObjectName.prop 去操作Object的时候,更改了内存空间的数据,但是并没有更改内存空间的位置,指针仍然是指向这块内存空间的,所以不会有警告报错),但还是不建议这样做。

     官网给出了解决方案:

    1)定义一个局部变量并用prop的值初始化它;

    2)定义一个计算属性,处理prop的值并返回。

我们对子组件进行改造:

子组件child数据 姓名: 您输入的姓名:{{ childName }} 年龄: 您输入的年龄:{{ childAge }} export default { // 父组件传来的数据,不是响应式的,并且基本类型的数据在子组价中直接修改会报出警告 props: ['myName', 'myAge'], // 为了更新这个data属性,就需要使用侦听器来监听props的变化 data () { return { // 如果仅仅是重新定义属性,会导致父组件发生改变而子组件无法响应(注意:只针对基本类型,如果是引用类型,仍旧是变化的) childName: this.myName, childAge: this.myAge } }, computed: { // computed 中不能设置响应式的data数据,更适合多对一的情况 ismyName () { // 监听父组件的myName,一旦获取到了父组件的值并且发生变化时会触发 return this.myName }, ismyAge () { return this.myAge } }, watch: {// 监听到了父组件值发生变化,这时监听器就可以操作响应式data,实现子组件同步父组件的更新 ismyName (newV, oldV) { console.log(newV, oldV) this.childName = newV // childName赋值 }, ismyAge (newV, oldV) { console.log(newV, oldV) this.childAge = newV // childName赋值 } } } h3 { font-size: 24px; font-weight: 400; margin-top: 0; margin-bottom: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; padding: 0 20px; text-align: center; color: #fff; } ul { margin: 10px; padding: 0; list-style: none outside none; border: 1px solid #ccc; } input { padding: 5px 10px; border-radius: 3px; border: 1px solid #ccc; margin: 10px; height: 30px; } .child { background: #bd6ea2; padding: 10px; border-radius: 5px; color: #fff; margin: 0 5px; }

 案例效果:

    现在修改子组件的,不会影响父组件的传递过来的prop。 

1.2、Prop 类型

    子组件定义 props 有三种方式:

// 第一种数组方式 props: [xxx, xxx, xxx] // 第二种对象方式 props: { xxx: Number, xxx: String} // 第三种对象嵌套对象方式 props: { xxx: { // 类型不匹配会警告 type: Number, // 对象或数组默认值必须从一个工厂函数获取 default: 0, required: true, // 自定义验证函数 validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } }

1.2.1、第一种数组方式

    数组方式:可以是静态的传递字符串,也可以是数字、布尔值、数组或者对象,但是后者需要使用到 v-bind指令。前面介绍过(v-bind 主要用于属性绑定,比方你的class属性,style属性,value属性,href属性等等,只要是属性,就可以用v-bind指令进行绑定),在上面(1.1 通过 Prop 传递数据)的案例中我们就用到了v-bind传递一个对象变量。

1)静态字符串

//main.js Vue.component('v-string', { // 声明 props props: ['message', 'myMessage'], // 就像 data 一样,prop 也可以在模板中使用 myMessage驼峰命名法 在模板中使用 kebab-case (短横线分隔式命名) // 同样也可以在 vm 实例中通过 this.message 来使用 template: '{{ message }} | {{ myMessage }}' }) //app.vue

运行结果:

2)动态对象

//main.js Vue.component('v-string', { // 声明 props , 注意字面量和使用v-bind指令传递的不同,v-bind传递会当做JavaScript 表达式 props: ['fatherMsg', 'myAge', 'fatherSz', 'userInfo'], template: '{{fatherMsg}} | {{myAge}} {{typeof myAge}} | {{fatherSz.length}} | {{userInfo.names}}' }) //app.vue export default { name: 'App', data () { return { fatherMsg: '我是父组件属性', myAge: 18, userInfo: { names: '张三', sex: '男' } } } }

运行结果:

1.2.2、第二种对象方式

    使用第二种对象的方式,可以验证参数的类型,如果不符合数据规格,Vue 会发出警告。把main.js中的props改成下面的格式,则控制台出现警告。

//main.js Vue.component('v-string', { // 声明 props props: { fatherMsg: String, myAge: String, fatherSz: Array, userInfo: Object }, template: '{{fatherMsg}} | {{myAge}} {{typeof myAge}} | {{fatherSz.length}} | {{userInfo.names}}' })

运行结果:

1.2.3、第三种对象嵌套对象方式

    第三种嵌套对象中的属性(type、default、required、validator)均为非必须。

    type可以是以下类型,type 还可以是一个自定义的构造函数(如:author: Person)

StringNumberBooleanArrayObjectDateFunctionSymbol

将main.js中替换成如下所示:

//main.js Vue.component('v-string', { // 声明 props props: { // 基础类型检查 (如果`null` 指允许任何类型) fatherMsg: String, // 可能是多种类型 myAge: [Number, String], // 必传且是数组 fatherSz: { type: Array, required: true, validator: function (value) { console.log(value[0]) // 2 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。 return value[0] > 2 } }, // 数组/对象的默认值应当由一个工厂函数返回,如果没有userInfo对象 则userInfo,names 默认返回defaultName userInfo: { type: Object, default: function () { return { names: 'defaultName' } } } }, template: '{{fatherMsg}} | {{myAge}} {{typeof myAge}} | {{fatherSz.length}} | {{userInfo.names}}' })

 运行结果:

1.3、非 Prop 的 Attribute

    什么是非Prop 的 Attribute 呢?(props是properties的缩写,attrs是attributes的缩写)在介绍Vue基础的时候,也介绍过properties(属性)和 attributes(特性)。

property是DOM中的属性,是JavaScript里的对象;attribute是HTML标签上的特性,它的值只能够是字符串,就比如我们的 DOM 元素自带的属性 class,style ,id;

    在Vue中一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 prop 定义的 attribute。对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。但是有两个比较特殊,class,style 不会替换,但是会合并。其他的属性基本上都会继承或者替换。

1.3.1、Attribute 继承

举个栗子:

在main.js中注册一个全局组件

Vue.component('v-com', { props: ['name', 'content', 'b', 'title'], template: `{{name}} | {{ content }} | {{b}} | {{title}}` })

在app.vue中

export default { name: 'App', data () { return { fatherMsg: '我是父组件属性' } } }

案例效果:

    在使用子组件时,我们定义了很多属性:【content="hello world"  a="3" :b="fatherMsg" c="4"  class="ddd" style="font-size: 16px;"  title="bt" value="fvalue" id="hh"  name="vcom" dir="ltr"】

    同时在子组件的根元素上定义了:【name='mydiv' id='mydiv' dir='rtl' title='l am div' style='color:blue' 】

    而子组件中我们只接收props: ['name','content', 'b', 'title']四个属性

    子组件中接收到了 ['name','content', 'b', 'title'],但是这四个属性就没有继承/替换到根元素上。根元素的id、dir被替换,a、c、value继承到了根元素上,而class 和 style进行了合并。

1.3.2、禁用 Attribute 继承

    如果不希望组件上的根元素继承attribute,可以在组件的选项中设置 inheritAttrs: false【inheritAttrs-继承属性的意思】

在main.js中加上inheritAttrs: false

Vue.component('v-com', { inheritAttrs: false, props: ['name', 'content', 'b', 'title'], template: `{{name}} | {{ content }} | {{b}} | {{title}}` })

案例效果:

    加上inheritAttrs: false,根元素的id、dir依旧不变,且a、c、value也没有继承到根元素上了。但是它始终不影响class 和 style的合并。

1.3.3、多个根节点上的 Attribute 继承-$attrs

    当我们知道了inheritAttrs的作用:是否继承来自父组件的属性(默认继承),那如果多个根节点或者不想到根节点继承呢?那就要使用到$attrs。我们再回头来看看官网给我们列举的案例:

//main.js Vue.component('base-input', { inheritAttrs: false, props: ['label', 'value'], template: ` {{ label }} | {{value}} | {{this.$attrs}} ` }) //App.vue

案例效果:

2、子组件向父组件传递数据

    prop实现了把父组件中的数据传递到子组件中,每次父组件更新时,子组件的所有 prop 都会更新为最新值。但是不能在子组件内部改变 prop,当然修改是有效的(可以通过this.$parent.name 访问到父组件中的属性),如果你这么做了,Vue 也会有警告提示。子组件向父组件传递数据,通过events - 自定义事件(回调参数)传递数据。

vm.$emit( eventName, […args] )

参数:

{string} eventName[...args]

触发当前实例上的事件。附加参数都会传给监听器回调。

    [每个Vue实例都实现了事件接口:使用$on(evntName)监听事件;使用$emit(eventName,optionalPayload)触发事件。父组件可以在使用子组件的地方直接用v-on来监听子组件触发的事件。]

2.1、通过 events 传递数据

   在上一个案例中其实也使用到了$emit。我们先看官网给出的一个例子。 子组件click事件,调用$emit,传入需要触发的父类自定义事件welcome,在父组件中使用子组件时对welcome绑定sayHi方法。

//在main.js 定义组件welcome-button Vue.component('welcome-button', { template: ` Click me to be welcomed ` }) //在App.vue 中使用组件(APP就是welcome-button父组件) export default { name: 'App', methods: { sayHi: function () { alert('Hi!') } } } 2.2、子组件向父组件传递一个值

    首先在main.js中定义一个子组件:v-testcom,并在this.$emit('childFn', this.message)中传递一个值this.message

let testCom = Vue.extend({ template: ` Send `, data () { return { // 默认 message: '我是来自子组件的消息' } }, methods: { click () { this.$emit('childFn', this.message) } } }) Vue.component('v-testcom', testCom)

在App.vue中使用子组件:



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3