Vue总结(一)

Vue总结(一)

1、脚手架

1.1 脚手架文件结构

├── node_modules: 存放依赖文件
├── public: 公共资源文件夹
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src: 源码目录
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── component: 存放组件
│   │   └── HelloWorld.vue
│   │── App.vue: 汇总所有组件
│   │── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件 
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件

1.2 关于不同版本的Vue

  1. vue.js与vue.runtime.xxx.js的区别:
    1. vue.js是完整版的Vue,包含:核心功能 + 模板解析器。
    2. vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
  2. 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template这个配置项,需要使用render函数接收到的createElement函数去指定具体内容。

1.3 vue.config.js配置文件

  1. 使用vue inspect > output.js可以查看到Vue脚手架的默认配置。
  2. 使用vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh

2、组件

组件化编码流程(通用)

  1. 实现静态组件:

    • 页面区域划分,抽取组件,使用组件实现静态页面效果
  2. 展示动态数据:

    • 数据的类型、名称是什么?
    • 数据保存在哪个组件?
    1. 交互:
    • 从绑定事件监听开始

2.1 ref属性

  1. 被用来给元素或子组件注册引用信息(id的替代者)
  2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  3. 使用方式:
    1. 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
    2. 获取:this.$refs.xxx
示例代码
<template>
	<div>
		<h1 v-text="msg" ref="title"></h1>
		<button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
		<School ref="sch"/> <!-- 给School标签元素打标识,相当于id -->
	</div>
</template>

<script>
	//引入School组件
	import School from './components/School'

	export default {
		name:'App',
		components:{School},
		data() {
			return {
				msg:'欢迎学习Vue!'
			}
		},
		methods: {
			showDOM(){
                //获取元素或对象
				console.log(this.$refs.title) //真实DOM元素
				console.log(this.$refs.btn) //真实DOM元素
				console.log(this.$refs.sch) //School组件的实例对象(vc)
			}
		},
	}
</script>

2.2 props配置项

  1. 功能:让组件接收外部传过来的数据

  2. 传递数据:<Demo name="xxx"/>

  3. 接收数据:

    1. 第一种方式(只接收):props:['name']

    2. 第二种方式(限制类型):props:{name:String}

    3. 第三种方式(限制类型、限制必要性、指定默认值):

示例代码

APP.vue

<template>
	<div>
        <!-- 传值,要使用props进行接收 -->
		<Student name="李四" sex="" :age="18"/>
	</div>
</template>

<script>
	import Student from './components/Student'

	export default {
		name:'App',
		components:{Student}
	}
</script>

School.vue

<template>
	<div>
		<h1>{{msg}}</h1>
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<h2>学生年龄:{{myAge+1}}</h2>
		<button @click="updateAge">尝试修改收到的年龄</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			console.log(this)
			return {
				msg:'哈哈哈',
				myAge:this.age
			}
		},
		methods: {
			updateAge(){
				this.myAge++ //修改复制后的数据,不修改原始数据
			}
		},
		//props简单声明接收
		// props:['name','age','sex'] 

		//接收的同时对数据进行类型限制
		/* props:{
			name:String,
			age:Number,
			sex:String
		} */

		//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
		props:{
			name:{
				type:String, //name的类型是字符串
				required:true, //name是必要的
			},
			age:{
				type:Number,
				default:99 //默认值
			},
			sex:{
				type:String,
				required:true
			}
		}
	}
</script>

再如:

//接收方式
props:{
	name:{
	type:String, //类型
	required:true, //必要性
	default:'老王' //默认值
	}
}

备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

2.3 组件的自定义事件

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:

    • A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
  3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @shijian="test"/><Demo v-on:shijian="test"/>

    2. 第二种方式,在父组件中:

      <Demo ref="demo"/>
      ......
      mounted(){
         this.$refs.xxx.$on('shijian',this.test)
      }
      
    3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

  4. 触发自定义事件:this.$emit('shijian',数据)

  5. 解绑自定义事件this.$off('shijian')

  6. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

  7. 注意:通过this.$refs.xxx.$on('shijian',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

功能需求:

子组件给父组件传数据,将子组件中的数据,展示到父组件中。

props配置项实现

App.vue

<template>
	<div class="app">
		<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
		<School :getXueXiaoName="getSchoolName"/>
	</div>
</template>

<script>
	import School from './components/School'

	export default {
		name:'App',
		components:{School},
		data() {
			return {
				msg:'你好啊!',
			}
		},
		methods: {
			getSchoolName(name) {
				console.log('App收到了学校名:',name)
			}
		},
	}
</script>

<style scoped>
	.app{
		background-color: gray;
		padding: 5px;
	}
</style>

School.vue

<template>
	<div class="school">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
		<button @click="sendSchoolName">把学校名给App</button>
	</div>
</template>

<script>
	export default {
		name:'School',
		props:['getXueXiaoName'], //声明接收父组件传过来的getXueXiaoName函数
		data() {
			return {
				name:'北京大学',
				address:'北京',
			}
		},
		methods: {
			sendSchoolName() {
				this.getSchoolName(this.name)
			}
		},
	}
</script>

<style scoped>
	.school {
		background-color: skyblue;
		padding: 5px;
	}
</style>
组件自定义事件实现

App.vue

<template>
	<div class="app">
		<h1>{{msg}},学生姓名是:{{studentName}}</h1>
	    <!--通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on)-->
		<!-- <Student @demo="m1"/> -->

		<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref,打标识)-->
		<Student ref="student" @click.native="show"/>
	</div>
</template>

<script>
	import Student from './components/Student'
	import School from './components/School'

	export default {
		name:'App',
		components:{School,Student},
		data() {
			return {
				msg:'你好啊!',
				studentName:''
			}
		},
		methods: {
			getStudentName(name,...params) { //接收一个或多个参数
				console.log('App收到了学生名:', name, params)
				this.studentName = name
			},
			m1() {
				console.log('demo事件被触发了!')
			},
			show(){
				alert(123)
			}
		},
		mounted() {
			this.$refs.student.$on('shijian01',this.getStudentName) //绑定自定义事件(绑定事件监听)
			// this.$refs.student.$once('demo',this.m1) 
      //绑定自定义事件(一次性),m1是demo事件触发时对应的处理函数(demo事件触发时,会回调m1函数)
		},
	}
</script>

<style scoped>
	.app{
		background-color: gray;
		padding: 5px;
	}
</style>

Student.vue

<template>
	<div class="student">
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<h2>当前求和为:{{number}}</h2>
		<button @click="add">点我number++</button>
		<button @click="sendStudentlName">把学生名给App</button>
		<button @click="unbind">解绑shijian01事件</button>
		<button @click="death">销毁当前Student组件的实例(vc)</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男',
				number:0
			}
		},
		methods: {
			add(){
				console.log('add回调被调用了')
				this.number++
			},
			sendStudentlName() {
				//触发Student组件实例身上的shijian01事件
				this.$emit('shijian01',this.name,666,888,900) //自定义事件,传递多个参数
				// this.$emit('demo')
				// this.$emit('click')
			},
			unbind(){
				this.$off('shijian01') //解绑一个自定义事件
				// this.$off(['shijian01','demo']) //解绑多个自定义事件
				// this.$off() //解绑所有的自定义事件
			},
			death(){
				this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
			}
		},
	}
</script>

<style lang="less" scoped>
	.student{
		background-color: pink;
		padding: 5px;
		margin-top: 30px;
	}
</style>


3、插槽

父组件向子组件传递带数据的标签,当一个组件有不确定的结构时, 就需要使用
slot 技术。

注意:插槽内容是在父组件(插槽使用者)中编译后, 再传递给子组件的。

作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件

分类:默认插槽、具名插槽、作用域插槽

3.1 默认插槽

Category.vue

<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<!-- slot标签,定义一个插槽(占个坑,等着组件的使用者进行填充) -->
		<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'] //声明接收组件使用者传过来的title属性值
	}
</script>

<style scoped>
	.category {
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3 {
		text-align: center;
		background-color: orange;
	}
	video {
		width: 100%;
	}
	img {
		width: 100%;
	}
</style>

App.vue(Category组件的使用者)

<template>
	<div class="container">
        <!-- title使用props接收 -->
		<Category title="美食" >
            <!-- img的内容是要放在插槽位置的东西 -->
			<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
		</Category>

		<Category title="游戏" >
			<ul>
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
		</Category>

		<Category title="电影">
			<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
		</Category>
	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				foods:['火锅','烧烤','小龙虾','牛排'],
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
				films:['《教父》','《拆弹专家》','《你好,李焕英》','《尚硅谷》']
			}
		},
	}
</script>

3.2 具名插槽

Category.vue

<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
		<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
		<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title']
	}
</script>

App.vue

<template>
	<div class="container">
		<Category title="美食" >
			<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
			<a slot="footer" href="http://www.meishi.com">更多美食</a>
		</Category>

		<Category title="游戏" >
			<ul slot="center">
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
			<div class="foot" slot="footer">
				<a href="http://www.yx.com">单机游戏</a>
				<a href="http://www.yx.com">网络游戏</a>
			</div>
		</Category>

		<Category title="电影">
			<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
			<template v-slot:footer>
				<div class="foot">
					<a href="http://www.dianying.com">经典</a>
					<a href="http://www.dianying.com">热门</a>
					<a href="http://www.dianying.com">推荐</a>
				</div>
				<h4>欢迎前来观影</h4>
			</template>
		</Category>
	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				foods:['火锅','烧烤','小龙虾','牛排'],
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
				films:['《教父》','《拆弹专家》','《你好,李焕英》','《尚硅谷》']
			}
		},
	}
</script>

3.3 作用域插槽

Category.vue

<template>
	<div class="category">
		<h3>{{title}}分类</h3>
        <!-- 将组件自身的一些东西(如:games),传给组件的使用者 -->
		<slot :games="games" msg="hello">我是默认的一些内容</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
		data() {
			return {
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
			}
		},
	}
</script>

<style scoped>
	.category {
		background-color: skyblue;
		width: 200px;
		height: 300px;
	}
	h3 {
		text-align: center;
		background-color: orange;
	}
	video {
		width: 100%;
	}
	img{
		width: 100%;
	}
</style>

App.vue

<template>
	<div class="container">
        
		<Category title="游戏">
            <!-- duixiang接收子组件传过来的东西,组件使用者(父组件)利用这些东西做不同的实现 -->
			<template scope="duixiang">
				<ul>
					<li v-for="(g,index) in duixiang.games" :key="index">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category title="游戏">
            <!-- 接收子组件传过来的东西,组件使用者(父组件)利用这些东西做不同的实现 -->
			<template scope="{games}"> <!-- 解构赋值 -->
				<ol>
					<li style="color:red" v-for="(g,index) in games" :key="index">{{g}}</li>
				</ol>
			</template>
		</Category>

		<Category title="游戏">
            <!-- 接收子组件传过来的东西,组件使用者(父组件)利用这些东西做不同的实现 -->
			<template slot-scope="{games}"> <!-- 解构赋值 -->
				<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
			</template>
		</Category>

	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
	}
</script>

<style scoped>
	.container,.foot{
		display: flex;
		justify-content: space-around;
	}
	h4{
		text-align: center;
	}
</style>

理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunnyboy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值