-
什么是组件?
组件是一个单独功能模块的封装,有属于自己的HTML模板,也应该有属于自己的数据data ,还有methods;组件模板必须有一个根(常用div) -
组件的基本使用:(含语法糖,含模板抽离,含对象抽离)这里是局部组件注册方式
基本步骤就是: 先创建一个组件mycpn,在里面写一个模板 template ,template通过 id 分离到页面上,之后将组件
mycpn 放到 vue实例对象里面的components 属性里面 进行注册,这样就可以在页面中直接使用mycpn这个组件了```javascript <body> <!-- 在这里我们就不使用 Vue.extend()方法创建组件构造器了 --> <div id="app"> <mycpn></mycpn> </div> <template id="cpn"> <!-- 在子组件模板里需要一个根 这个根我们可以搞个div --> <div> <h3>这是我创建的第一个组件 组件名为 mycpn 以后就使用这个方式来创建使用组件</h3> </div> </template> <script> // 注册组件 使用语法糖 const mycpn = { // 子组件将数据存放在data中 且 data属性为一个函数 // 原因:如果data是一个对象,所有组件都会用一个data,就会产生连锁反应(组件的复用),使用函数每次都会返回新的对象,不会产生影响 data() { return { } }, template: '#cpn', methods: {}, components: {} } const app = new Vue({ el: '#app', data: {}, methods: {}, components: { // 对象字面量属性增强写法 mycpn } }); </script>
-
全局组件和局部组件
全局组件 使用 Vue.component() 方法
局部组件在vue实例里面创建 components 里面注册<body> <div id="app"> <mycpn></mycpn> <hr> <mycpn1></mycpn1> </div> <template id="cpn"> <div> <h4>这是全局组件的注册方式</h4> </div> </template> <template id="cpn1"> <div> <h4>这是局部组件的注册方式</h4> </div> </template> <script> // 1.全局组件 使用 Vue.component() 方法 Vue.component('mycpn', { template: '#cpn' }) // 2.局部组件在vue实例里面创建 components 里面注册 const app = new Vue({ el: '#app', data: {}, methods: {}, components: { mycpn1: { template: '#cpn1' } } // 也可以将 mycpn1 组件抽出去 写成 const mycpn1 = { template: '#cpn1'} }); </script> </body>
-
父组件和子组件
按我自己的理解就是:有俩个组件(组件1和组件2),组件 1 ,2 分别有自己的模板template,组件1放到组件2里面注册(components下面)然后组件2 放到vue实例里面注册。二者都注册完之后,特别注意:组件1要在组件2模板里使用
之后将组件2放到页面上使用时,就可以看到组件1和组件2。这就是所谓的父子组件,其中组件1为组件2的孩子。<body> <div id="app"> <mycpn></mycpn> </div> <template id="cpn"> <div> <h3>我是父组件</h3> <hr> <!-- 注意: 子组件注册完之后 要在父模板里使用 这样当父组件加载到页面上时才能将子组件显示出来 --> <cpn1></cpn1> </div> </template> <template id="ccpn"> <div> <h3>我是子组件</h3> </div> </template> <script> const cpn1 = { template: '#ccpn' } // 将cpn1 组件放到 mycpn 里面注册 mycpn组件放到 Vue实例里面注册 const mycpn = { template: '#cpn', components: { cpn1 } } const app = new Vue({ el: '#app', data: {}, methods: {}, components: { mycpn } }); </script> </body>
-
组件中数据的存放问题(data 属性里面存)
-
组件是不能直接访问Vue实例对象里面的数据的 ;
-
组件有自己存放数据的地方 data属性 ;
-
只不过 data 是一个函数而且返回的是一个对象 对象里面存放数据
-
原因:Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
<body> <div id="app"> <cpn></cpn> </div> <template id="cpn"> <div> <h3>这是组件,现在我需要获取组件的数据</h3> <span>这是子组件里面的数据:{{students}}</span> <ul> <h4>这是获取组件里面的数组对象数据</h4> <li v-for='items in books'>{{items.name}} {{items.price}}</li> </ul> </div> </template> <script> const cpn = { template: '#cpn', data() { return { // 存放一个对象 students: { name: '方敬', age: 22, height: 180 }, // 存放一个数组对象 books: [{ id: 01, name: '斗罗大陆', price: '$180.00' }, { id: 02, name: '斗破苍穹', price: '$189.00' }, { id: 03, name: '武动乾坤', price: '$182.00' } ] } } } const app = new Vue({ el: '#app', data: {}, methods: {}, components: { cpn } }); </script> </body>
-
-
组件通信—父组件向子组件传递数据
方法: 在子组件中通过 props 来声明接收父组件的数据
props 的值有俩种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称。
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。对象方法用的较多(在子组件
<mycpn></mycpn>
用v-bind绑定传值 : 子组件的数据=父组件的数据,:mymessage=‘message’ )
方式一:字符串数组
<body> <div id="app"> <mycpn :mymessage='message'></mycpn> </div> <template id="cpn"> <div> <!-- join 将数组转换成字符串 --> <h4>这是从父组件接收过来的数组数据:{{mymessage.join()}}</h4> </div> </template> <script> // 父组件向子组件传递数据 // 方法: 在子组件中通过 props 来声明接收父组件的数据 // props 的值有俩种方式:方式一:字符串数组,数组中的字符串就是传递时的名称。 //方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。 const mycpn = { template: '#cpn', // 声明需要从父亲接收到的数据 props: ['mymessage'] } const app = new Vue({ el: '#app', data: { // 字符串数组 message: ['方敬是', '傻逼'], }, methods: {}, components: { mycpn } }); </script> </body>
方式二:对象
<body> <div id="app"> <mycpn :cmessage='cmessage'></mycpn> </div> <template id="cpn"> <div> <!-- join 将数组转换成字符串 --> <h4>这是从父组件接收过来的对象数据: {{cmessage.name}} {{cmessage.age}}</h4> </div> </template> <script> // 父组件向子组件传递数据 const mycpn = { template: '#cpn', // 声明需要从父亲接收到的数据 props: { cmessage: { type: Object, default() { return {} } } } } const app = new Vue({ el: '#app', data: { cmessage: { name: '刺客短裤', age: 18 } }, methods: {}, components: { mycpn } }); </script> </body>
-
组件通信—子组件向父组件传递 数据/事件(通过自定义事件)
在子组件中,通过$emit()来触发事件。在父组件中,通过v-on来监听子组件事件。
需求:我们之前做过一个两个按钮+1和-1,点击后修改counter。 我们整个操作的过程还是在子组件中完成,但是之后的展示交给父组件。
这样,我们就需要将子组件中的counter,传给父组件的某个属性,比如total。<body> <div id="app"> <!-- v-on 监听自定义事件 --> <childcpn @increment='totalChange' @decrement='totalChange'></childcpn> <h3>点击次数 : {{total}}</h3> </div> <template id="cpn"> <div> <h3>计数:{{counter}}</h3> <button @click='increment'>+</button> <button @click='decrement'>-</button> </div> </template> <script> // 子组件向父组件传递 数据/事件 通过自定义事件 // 在子组件中,通过$emit()来触发事件。 // 在父组件中,通过v-on来监听子组件事件。 const childcpn = { template: '#cpn', data() { return { counter: 0 } }, methods: { increment() { this.counter++ // 在这里使用 $emit 来触发increment事件 并将数据传过去 在父组件中使用v-on来监听子组件事件 this.$emit('increment', this.counter) }, decrement() { this.counter-- // 在这里使用 $emit 来触发increment事件 并将数据传过去 在父组件中使用v-on来监听子组件事件 this.$emit('decrement', this.counter) } } } const app = new Vue({ el: '#app', data: { total: 0 }, methods: { // 监听事件之后 在父组件里来接收数据 totalChange(counter) { this.total = counter } }, components: { childcpn } }); </script> </body>
-
组件访问—父组件访问子组件($refs,少用 $children)
$refs的使用- $refs和ref指令通常是一起使用的。
- 首先,我们通过ref给某一个子组件绑定一个特定的ID。在父组件模板里,找到子组件的使用并绑上ID。
- 其次,通过this.$refs.ID就可以访问到该组件了。
<body> <div id="app"> <childcpn1 ref='child1'></childcpn1> <childcpn2 ref='child2'></childcpn2> <button @click='showmessge()'>点击</button> </div> <template id="cpn1"> <div> <h3>我是第一个孩子 哈哈哈哈哈</h3> </div> </template> <template id="cpn2"> <div> <h3>我是第二个孩子 嘻嘻嘻嘻嘻</h3> </div> </template> <script> // 通过 $refs 来访问子组件 给子组件绑定 ref 相当于id const childcpn1 = { template: '#cpn1', data() { return { message: '方敬是傻逼' } }, methods: { bnClick() { console.log('......点击了'); } } } const childcpn2 = { template: '#cpn2', data() { return { message: '方敬不是傻逼' } } } const app = new Vue({ el: '#app', data: {}, methods: { showmessge() { console.log(this.$refs.child1.message); // 调用第一个孩子的方法 console.log(this.$refs.child1.bnClick()); console.log(this.$refs.child2.message); } }, components: { childcpn1, childcpn2 } }); </script> </body>
-
组件访问—子组件访问父组件($root 直接访问祖宗,避免多重套娃的连锁反应 少用 $parent)子访问父 在子模板里写操作
-
slot 插槽的基本使用
作用:以让使用者根据自己的需求,决定插槽中插入什么内容 是搜索框,还是文字,还是菜单。由调用者自己来决定
使用: 就是在子组件的模板里添加一个<slot></slot>
标签<body> <div id="app"> <mycpn> <a href="">百度</a> </mycpn> <mycpn> <h3>这是我替换插槽的内容 哈哈哈哈哈</h3> </mycpn> <mycpn></mycpn> </div> <template id="cpn"> <div> <h4>下面是插槽哦,里面的内容可以替换</h4> <slot>我是插槽哦,我可以被替换成其他哦</slot> <hr> </div> </template> <script> // 插槽的作用: 可以让使用者根据自己的需求,决定插槽中插入什么内容 是搜索框,还是文字,还是菜单。由调用者自己来决定 const mycpn = { template: '#cpn' } const app = new Vue({ el: '#app', data: {}, methods: {}, components: { mycpn } }); </script>
-
具名插槽的使用(这里使用Vue 3 的 v-slot )
注意:v-slot 是在组件里面添加一个 template 标签 然后在这个标签里写v-slot 并不是在 模板里面写v-slot
v-slot: 的语法糖为 #
注:区分俩个template的不同 -
作用域插槽 (父组件替换插槽的标签,但是内容由子组件来提供)
使用场景:父组件向子组件拿数据
我们选择将包含所有插槽prop的对象命名为slotProps
需求:子组件中包括一组数据,比如:pLanguages: [‘JavaScript’, ‘Python’, ‘Swift’, ‘Go’,‘C++’]
需要在多个界面进行展示: 某些界面是以水平方向一一展示的, 某些界面是以列表形式展示的, 某些界面直接展示一个数组这里也使用 Vue3 的
v-slot:default = 'slotProps'
子组件模板template里的 slot 用:data='子组件里的数据'
来绑定数据
<body> <div id="app"> <mycpn> <!-- 水平显示 --> <template v-slot:default='slotProps'> <!-- join() 将数组转换成字符串 --> <span>{{slotProps.data}}</span> <span>{{slotProps.data.join()}}</span> </template> </mycpn> <mycpn> <!-- 列表形式显示 --> <template v-slot:default='slotProps'> <ul> <li v-for='item in slotProps.data'>{{item}}</li> </ul> </template> </mycpn> </div> <template id="cpn"> <div> <slot :data='pLanguages'></slot> <hr> </div> </template> <script> const mycpn = { template: '#cpn', data() { return { pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++'] } } } const app = new Vue({ el: '#app', data: {}, methods: {}, components: { mycpn } }); </script> </body>
-
编译的作用域
父组件模板的所有东西都会在父级作用域内编译;
子组件模板的所有东西都会在子级作用域内编译;
就近原则,往上查 。
在谁家用谁的东西,在vue模板就去找vue实例 ,组件的模板找自己的作用域。 -
不懂就看官方文档:https://v3.cn.vuejs.org/
Vue 组件化学习(组件的基本使用,组件之间的数据传递,插槽slot)
最新推荐文章于 2024-05-13 10:16:48 发布