IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue2学习笔记2——B站 -> 正文阅读

[JavaScript知识库]Vue2学习笔记2——B站

3 组件化开发

为了提高代码复用性,使用组件化开发,将一串拥有独立功能、可以接受参数、可渲染控件的代码封装起来,并给与一个名字,在使用时与其他html基础元素相同。

组件其实就是可复用的Vue实例,和new Vue一样,存在data、computed、watch、methods等属性,而el是根实例特有的!

注意:vue2要求组件模板为单根元素,vue3无该要求

组件构建三步骤:

  1. 创建组件构造器:Vue.extend()
  2. 注册组件:Vue.component()
  3. 使用

注意:目前建议直接使用注册组件方法一步到位合并1,2两步:

Vue.component("abc",{
	template:`<div></div>`,
})

在这里插入图片描述

组件使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="../js/vue.js"></script>
</head>
<body>
    <div id="app">
        <button-counter></button-counter>
    </div>
    <script>
    // 全局组件注册
        Vue.component('button-counter', {
            data: function () {
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
        })
        new Vue({
            el: '#app'
        })
    </script>
</body>
</html>

3.1 全局组件和局部组件

全局组件:可以在所有的Vue实例下使用(可以有多个Vue实例,但是不推荐)

Vue.component('abc',abc)

局部组件:是在Vue实例下注册的组件

new Vue({
components:{
'abc':abc
}
})

3.2 父组件和子组件

在父组件构造器中注册的组件称为父组件的子组件

const cp2 = Vue.extend({
	template:`
		<div>
			<p>222</p>
		</div>
	`,
})
const cp1 = Vue.extend({
	template:`
		<div>
			<p>111</p>
			<cp2></cp2>
		</div>
	`,
	components:{
		cp2:cp2
	}
})

注意:如果想在当前作用域中使用自定义组件,必须在当前的作用域中注册该组件,不存在传递!

其实在父组件中,vue编译父组件的时候,子组件就被替换成对应的模板了,最终当前作用域中只存在父组件编译好的所有模板。即子组件不是在当前作用域中编译解析的,所以在当前作用域中需要使用子组件必须再次注册。

3.2.1 父组件直接访问子组件 $children

父组件如果向直接访问子组件可以使用:$children$refs

this.$children获取到的是当前组件的所有子组件,可以通过遍历来访问子组件中的方法或者属性

更好的目的性更明确地是使用$refs,使用方法:

  1. 在需要访问的组件上使用ref定义属性:<abc ref="a"></abc>
  2. 在需要访问的地方使用:this.$refs.a即可

3.2.2 子组件访问父组件 $parent

使用方法:this.$parent

不建议使用,耦合性太高了

3.2.3 直接访问Vue实例(顶层)$root

this.$root

3.3 模板抽离

将模板抽离出js内,放到html中去写,有两种方式

  1. 使用script标签,类型为text/x-template
<script type="text/x-template" id="cp1">
<div>
	<h2>abc</h2>
</div>
</script>
<script>
Vue.component('cp1',{template:'#cp1'}
</script>
  1. 使用template标签
<template id="cp1">
<div>
	<h2>abc</h2>
</div>
</template>
<script>
Vue.component('cp1',{template:'#cp1'}
</script>

3.4 组件data

组件的data必须是一个函数! 不能是一个对象,这样每个组件实例才能获得一份独立的数据拷贝!否则所有组件状态会相同!

data: function () {
  return {
    count: 0
  }
}

因为如果不是函数,则每次复用组件会导致组件内部状态一样,因为获取到的是同一个对象

3.5 组件传值props(父组件–>子组件)

Prop可以在组件上注册自定义的属性,props属性接收一个变量数组[]

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post>
<!--如果需要传递变量过去,需要使用v-bind-->
<blog-post :title="msg"></blog-post>

props支持验证和默认值设置,这需要使用对象来传递

Vue.component('blog-post', {
  props: {
	title: String,
	message: [String, Number],
	name: {
		type: String,
		required: true,
		default: "pp"
		}
	hobby: {
		type: Array,
		default: function(){return ["jump","eat"]}
		}
	other: {
		type: Object,
		default: function(){return {abc:"aaa"}}
		}
	},
  template: '<h3>{{ title }}</h3>'
})

注意:这几种props写法都可以,一种是数组,一种是对象。其中对象写法可以定义类型和是否必须,当类型为数组或者对象时,对于低版本Vue的默认值必须是一个函数
类型可以定义为:String|Number|Boolean|Array|Object|Date|Function|Symbol

当然也可以自定义类型:

function Person(a, b){
	this.a = a
	this.b = b
}

props:{
	author: Person
}

注意:在标签属性中不支持驼峰命名,如果在vue对象中的变量是驼峰命名,可以在v-bind的属性上使用-进行分割,如:v-bind:abC=""转化成v-bind:ab-c=""

3.6 组件事件监听$emit(子组件–>父组件)

情景:当子组件事件需要让父组件监听行为并作出一些改变时:
方法一:子组件无需复杂操作,仅仅传递参数给父组件:使用v-on:自定义事件="函数"v-on:事件=$emit("自定义事件")组合来实现
方法二:子组件需要复杂操作,并传递参数给父组件:使用props传递函数

3.6.1 方法一

父组件:定义监听自定义事件

<blog-post v-on:enlarge-text="run"></blog-post>

子组件:定义触发方法,抛出对应的自定义事件名

<button v-on:click="$emit('enlarge-text')">Enlarge text</button>

<!--或者在子组件的方法中使用:this.$emit(自定义事件,参数):methods:{crun(x){this.$emit('enlarge-text',x)}}-->
<button v-on:click="crun">Enlarge text</button>

相当于子组件通过标准事件抛出自定义事件,然后父组件监听到该自定义事件,并触发相应函数进行操作

有时候,需要对自定义事件传参,则须要用到$emit(自定义事件名,参数),使用第二个参数进行传参,传递的参数在监听函数中使用$event获取,此处的$event就是参数,可以直接使用

<!--方法中:this.$emit('enlarge-text',0.1)-->
<button v-on:click="$emit('enlarge-text', 0.1)">Enlarge text</button>

<blog-post v-on:enlarge-text="postFontSize += $event"></blog-post>

更常用的是通过函数参数来获取

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

在这里插入图片描述

3.6.2 方法二

当然,对于子组件向父组件发起控制也可以通过props来做,具体思路:(由于回调函数定义在父组件中,可以更改父组件状态,而触发操作在子组件中,相当于子组件控制父组件)

  1. 父组件定义一个回调函数,将这个回调函数传递给子组件的绑定属性
  2. 子组件某个操作调用过程中调用父组件传过来的回调函数,并传递值即可

3.7 组件插槽slot

插槽:让组件扩展性更强,抽取共性,插槽用来替换个性
插槽用于在自定义组件中放置可以显示在自定义标签中间的内容,即自定义标签中间的部分会替换到插槽位置

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

<alert-box>
  Something bad happened.
</alert-box>

插槽中间可以放其他标签,作为默认值,如果自定义标签中间存在标签,则默认值被该标签替换,否则显示默认标签
<slot><div>123</div></slot>

如果存在多个插槽,则会重复替换,如果有多个标签,则会一起替换到插槽位置

特别注意:插槽上不要写css或者判断,因为会被直接替换掉!可以采取间接方法用div包裹插槽,然后在div上进行判断和样式

3.7.1 具名插槽

多插槽情况,如果插槽具有name属性,则必须替换时使用slot属性指定替换的插槽:

<abc>
	<div slot="a">444</div>
</abc>

<div class="abc">
  <strong>Error!</strong>
  <slot name="a"></slot>
  <slot name="b"></slot>
  <slot name="c"></slot>
</div>

3.7.2 作用域插槽

作用域插槽相当于将本作用域的一些数据提供到外部使用,即暴露本作用域中的内容

<!--组件中-->
<template id="myabc">
    <div>
        <slot :mydata="abc">
            <span>默认显示:{{abc}}</span>
        </slot>
    </div>
</template>

<script>
..
// 注册组件
myabc: {
    template: "#myabc",
    data:function(){
        return{
            abc: 1111
        }
    }
}
...
</script>

<!--使用-->
<myabc>
    <template slot-scope="myslot">
        <span>改写显示:{{myslot}}</span>
    </template>
</myabc>

分析使用过程:组件中在slot标签上定义自定义属性,然后赋值,在组件外部(即使用该组建的组件中)可以通过:slot-scope获取到内部的slot上定义的自定义属性!最终展示结果为:改写显示:{ "mydata": 1111 }

注意:如果组件中定义了多个slot,则会分别替换,且每个替换得到的slot对象和对应slot的暴露属性一致

3.8 动态组件

动态组件用于在事件触发后动态加载组件,改变is的值即可改变渲染的对象,接收的对象都被视为Vue组件(value需要加.prop)

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

4 模块化开发

原生js进行编写时会导致全局变量同名问题,还有引入顺序也会导致一些问题,解决方法:模块化封装

模块化封装基本思想:使用匿名函数立即调用形式+闭包:(function(){})(),因为函数有自己的作用域,不会导致同名,但是又出现代码复用性无的问题,因为拿不到函数内的变量或者函数,所以还需要通过闭包

var moduleA = (
	function(){
		var obj = {}
		var f = function(x){console.log(x)}
		var name = "pp"
		obj.name = name
		obj.f = f
		return obj
	}
)()
// 此时moduleA中存在自己的作用域和属性,只需要保证全局中module名不重复即可

常见的模块化规范:CommonJS | AMD | CMD | ES6Modules
nodejs中模块化使用的CommonJS规范

模块化规范核心:导入、导出

4.1 CommonJS

// 导出
module.export = {
	flag: true,
	run(){},
	name: "pp"
}

// 导入
let {flag,run,name} = require('./xxx.js)
// 或
let x = require('./xxx.js)
let flag = x.flag

4.2 ES6 export/import

// 导出:写法1
export let name = 'pp
export let age = 12
// 导出:写法2
let name = "pp"
let age = 213
export {name,age}

// 导入
import {flag,sum} from './xxx.js'
console.log(flag)

// html中使用
<script src="./xxx.js" type="module"></script>

4.2.1 export default

导出默认模块,普通导出:导出的名字和导入的名字必须相同才能正确获取

export default导出则为匿名,可以在导入的时候去自定义名字,一个文件default导出的只能存在一个,导入的时候不需要{},表示导入默认导出项

export default x

import y from 'xxx.js'

4.2.2 统一全部导出

由于对于非default导入需要 保证导入的变量名和导出的相同,当导入变量很多,则可以采用导入全部作为一个变量,然后去使用

// 全部导出
import * as x from 'xxx.js'
console.log(x.name)
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-21 12:06:15  更:2021-10-21 12:08:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:33:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码