vue2基础配置、基本语法、经验

目录

1、vue.config.js相关配置,代理服务器,vue-resource

2、vue原型、原型链

3、vuex插件的使用

4、vue路由的使用

n、vue基础知识

n+1、vue基础经验分享


1、vue.config.js相关配置,代理服务器,vue-resource

lintOnSave:false
/*用途
设置是否在开发环境下每次保存代码时都启用 eslint验证。
value:   
false:关闭每次保存都进行检测
true:开启每次保存都进行检测,效果与warning一样
‘warning’:开启每次保存都进行检测,lint 错误将显示到控制台命令行,而且编译并不会失败。
‘error’:开启每次保存都进行检测,lint 错误将显示到浏览器页面上,且编译失败。
‘default’:同’error’
*/

axios:发送json请求
使用:1、npm i axios
2、【A】
	import axios from 'axios'
	methods: {
		methodName(){
			//请求前更新List的数据
			this.$bus.$emit('updateEventName',{...})
			axios.get(`https://api.github.com/search/users?q=${this.data}`).then(
				response => {
					console.log('请求成功了')
					//请求成功后更新List的数据
					this.$bus.$emit('eventName',{xxx:response.xxx.xxx,...})
				},
				error => {...}
			)
		}
向服务器发送json请求
vue.config.js
	配置代理:
	假设服务器请求地址为:http://127.255.255.254:5000/project
	def-api:自定义请求前缀 ,避免自己有重名项目
	【App】发请求: axios.get('http://localhost:8080/def-api/project').then(response=>{},error=>{})

//开启代理服务器
	devServer: {
	proxy: {
	  '/def-api': {
			target: 'http://127.255.255.254:5000',
			【此时代理服务器转发到了http://127.255.255.254:5000/def-api/project,所以要重写目标url】
			pathRewrite:{'^/def-api':''},//把正则里的路径rewrite为空字符串
			// ws: true, //用于支持websocket
			// changeOrigin: true //用于控制请求头中的host值,true为目标获取服务器的,false为自己的代理服务器的(8080)
			}
		}
	}



vue-resource插件 对XHR的封装,发送json请求 【vue1.0经常用】
使用:1、npm i vue-resource
2、
main.js
	import vueResource from 'vue-resource'
	Vue.use(vueResource)//应用插件后,所有的vm vc都有了一个$http
【A】
	methods: {
		methodName(){
			this.$http.get(`https://api.github.com/search/users?q=${this.data}`).then(
				response => {
					console.log('请求成功了')
					this.$bus.$emit('eventName',{xxx:response.xxx.xxx,...})
				},
				error => {}
			)
		}
	}


2、vue原型、原型链

原型:每一个javascript对象(除null外)创建的时候,都会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。这样就形成了原型链
	__proto__是实例指向原型的属性
	prototype是对象或者构造函数指向原型的属性
	  var cat = new Animal()


 

3、vuex插件的使用

VueX:专门在Vue中实现集中式状态管理的一个Vue插件 vue.use(plugin),核心:store,用于管理Actions,Mutations,State
	多个组件依赖同一状态
	来自不同组件的行为需要变更同一状态
#使用:1、npm install vuex@next --save
	
#2、组件发送数据=========================================================================
【A组件】	
	methods: {
		methodName(){
			this.$store.dispatch('xxx',this.data)//xxx与Actions对话,然后到Mutations
			//如果只是简单的操作数据,则使用commit,xxx则忽略Actions,直接到Mutations
			或者this.$store.commit('XXX',this.data)
		},
	获取数据:$store.state.dataName
			$store.getters.propName
		
#3、项目下新建store文件夹,下新建index.js文件,用于创建vuex中的store====================
index.js进行创建导出store 这样vc就可以通过.$store共享数据
	import Vue from 'vue'
	import Vuex from 'vuex'
	Vue.use(Vuex)//先使用vuex插件,再创建store
	
	//准备Actions——用于响应组件中的动作、业务逻辑、ajax请求------------------------
	const actions = {
		xxx(context,value){//context:小型的store对象即context;value:组件传的值
			//业务逻辑
			context.commit('XXX',value)
		},
		或者
		xxx(context,value){
			//业务逻辑1
			context.dispatch('demo1',value)【可省略】
		},
		demo1(context,value){
			//业务逻辑2
			context.commit('XXX',value)}
	}
	//准备Mutations——用于操作数据state【一般key值大写,来与Actions的key区分】---------
	const mutations = {
		XXX(state,value){//state:数据; value:组件传来的值
			state.dataName += value
		},
	}
	//准备State——用于存储数据----------------------------------------------------
	const state = {
		dataName:dataValue
	}

	//准备getters——用于将state中的数据进行加工【可省略】
	const getters = {
		propName(state){
			return state.dataName*10
		}
	}

	//创建并导出store【与创建vue结构相似】 调用构造函数Store---------------------
	export default new Vuex.Store({
		actions,【key与value重名,于是简写】
		mutations,
		state,
		getters
	})
	
#4、main.js进行引入=======================================================================
	import store from './store'
	new Vue({
		store,【简写形式】
	})
=========================================================================================
优化vuex,方便取出store中存取和处理过的state和getters的数据,
		方便提交到actions和mutations中
组件中:
	import {mapState,mapGetters,mapActions,mapMutations} from 'vuex'

	mapState方法:用于帮助我们映射state中的数据为计算属性------------------------------------
	computed: {
		//借助mapState生成计算属性:sum、school、subject(对象写法)
		 ...mapState({sum:'sum',school:'school',subject:'subject'}),//扩展运算符
			 
		//借助mapState生成计算属性:sum、school、subject(数组写法)
		...mapState(['sum','school','subject']),
	},
	mapGetters方法:用于帮助我们映射getters中的数据为计算属性---------------------------------

	computed: {
		//借助mapGetters生成计算属性:bigSum(对象写法)
		...mapGetters({bigSum:'bigSum'}),

		//借助mapGetters生成计算属性:bigSum(数组写法)
		...mapGetters(['bigSum'])
	},
	mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx,this.data)的函数--
		#@click="methodName(data)" 在模板中绑定事件时传递好参数【this.data】
	methods:{
		//发送给mapActions,对象形式
		...mapActions({methodName:'xxx'})

		//发送给mapActions,数组形式
		...mapActions(['methodName','xxx'])
	}
	mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(XXX,this.data)的函数--
		#@click="methodName(data)" 在模板中绑定事件时传递好参数【this.data】
	methods:{
		//发送给mapActions生成,对象形式
		...mapMutations({methodName:'XXX'}),
		
		//发送给mapMutations生成,对象形式
		...mapMutations(['methodName','XXX']),
	}
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是MpuseEvent对象。
=======================================================================================
vuex模块化:
main.js
	import Vue from 'vue'
	import App from './App.vue'
	import store from './store'

	//使用插件
	Vue.use(vueResource)

	//创建vm
	new Vue({
		...
		store,
		}
	})

module1.js、module2.js 将各自模块所需属性进行拆分
	export default {
	namespaced:true,//开启命名空间
	actions:{
		...
	},
	mutations:{
		...
	},
	state:{
		a1:xxx,
		a2:xxx
	},
	getters:{
		gettersName1(state){
			return state.a1*10
		}
	},
	}
index.js
	import Vue from 'vue'
	import Vuex from 'vuex'
	import moduleName1 from 'xxx/module1'
	import moduleName2 from 'xxx/module2'
	Vue.use(Vuex)
	export default new Vuex.Store({
		modules:{
			moduleNamea:moduleName1,
			moduleNameb:moduleName2
		}
	})
【A组件】
	@click="methodName(data)"
	用数据:a1 a2
	computed:{
			//借助mapState(数组写法)
			...mapState('moduleNamea',['a1','a2']),
			...mapState('moduleNameb',['b1','b2']),
			//借助mapGetters(数组写法)
			...mapGetters('moduleNamea',['gettersName1'])
		},
		methods: {
			//借助mapMutations(对象写法)
			...mapMutations('moduleNamea',{methodName:'XXX'}),
			//借助mapActions(对象写法)
			...mapActions('moduleNamea',{methodName:'xxx'})
		},
或者
【B】
import {nanoid} from 'nanoid'
	export default {
		computed:{
			b1(){
				return this.$store.state.moduleNameb.b1
			},
			gettersName1(){
				return this.$store.getters['moduleNameb/gettersName1']
			}
		},
		methods: {
			methodName1(){
				this.$store.commit('moduleNameb/XXX',this.data)
			},
			methodName2(){
				this.$store.dispatch('moduleNameb/xxx',this.data)
			},
		},
	}

	
	
	
	

4、vue路由的使用

/*路由
	理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
		一般组件使用:直接<A/> 【一般放在components文件夹】
		路由组件:定义路由匹配规则规则,<router-link>匹配规则<router-view>展示组件【一般放在pages文件夹】
	1. 后端路由: 
		1) 理解:value 是 function, 用于处理客户端提交的请求。 
		2) 工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数 来处理请求, 返回响应数据。
	2. 前端路由: 点击导航区只跳转展示区,不跳转页面,数据一般从服务器ajax请求过来
		1) 理解:value 是 component,用于展示页面内容。 
		2) 工作过程:当浏览器的路径改变时, 对应的组件就会显示*/
1.基本使用 为了使用SPA(single page web application)应用,	

	安装vue-router插件库,命令:npm i vue-router【注意vueroter4只能在vue3中使用,vueroter3才能在vue2中使用】
	应用插件:Vue.use(VueRouter)
	建立router文件夹下,index.js文件,用于创建路由器
	
main.js
	import VueRouter from 'vue-router'
	import router from './router'
	Vue.use(VueRouter)
	new Vue({
		router:router
	})
	
index.js	
	import VueRouter from 'vue-router'
	import A from '../pages/A'
	import B from '../pages/B'
	export default new VueRouter({
		routes:[//路由匹配规则
			{
				path:'/a',//如果url路径为/a,则使用A组件
				component:A
			},
			{
				path:'/b',
				component:B
			}
		]
	})

【App】//vue-router会把<router-view/>转成<a/>标签
	//实现切换(active-class可配置该元素被激活时的样式;active:高亮)
	#导航区:<router-link active-class="active" to="/a">在导航区点我,展示区跳转到A组件</router-link>
	
	//vue中靠router-view:指定组件展示位置
	#展示区:<router-view></router-view>
	
2.几个注意点
	路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
	通过导航区切换了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
	每个组件都有自己的$route属性,里面存储着自己的路由信息。
	整个应用只有一个router,可以通过组件的$router属性获取到。
	
3.多级路由(嵌套路由)
	配置路由规则,使用children配置项:
index.js	
	import VueRouter from 'vue-router'
	import A from '../pages/A'
	import B from '../pages/B'
	export default new VueRouter({
	routes:[
		{
			path:'/a',
			component:A,//一级路由
			children:[ //通过children:[] 配置子级路由
				{
					path:'b', //此处一定不要加正斜杠
					component:B //二级路由
				},
				{
					path:'c',//此处一定不要加正斜杠
					component:C
				}
			]
		}
	]
	【App】
		<router-link to="/a">在导航区点我,展示区跳转到A</router-link>
	【A】跳转要写完整路径
		<router-link to="/a/b">在导航区点我,展示区跳转到B</router-link>
		<router-link :to="{path:'/a/c'}">在导航区点我,展示区跳转到C</router-link>
		
4.命名路由
	作用:可以简化路由的跳转。
	使用:给路由命名:
index.js	
	import VueRouter from 'vue-router'
	import A from '../pages/A'
	import B from '../pages/B'
	export default new VueRouter(
		{
			path:'/a',
			component:A,
			children:[
				{
					path:'b',
					component:B,
					children:[
						{
							name:'hello' //给路由命名
							path:'c',
							component:C,
						}
					]
				}
			]
		})
	<!--简化前,需要写完整的路径 -->
【B】	<router-link to="/a/b/c">跳转</router-link>

	<!--简化后,直接通过名字跳转 -->
	<router-link :to="{name:'hello'}">跳转</router-link>

	<!--简化写法配合传递参数 -->
	<router-link 
		:to="{
			name:'hello',
			query:{
			   id:data.xxx,
				title:'你好'
			}
		}">跳转</router-link>
		
5.路由的query参数
	#传递参数【场景:A组件下有B组件下有C组件,假设在index.js配置好了规则】
	<!-- 跳转并携带query参数,to的字符串写法 -->
【B】	<router-link :to="`/a/b/c?id=${data.xxx}&title=hello`">跳转</router-link>
					
	<!-- 跳转并携带query参数,to的对象写法 -->【推荐】
	<router-link 
		:to="{
			path:'/a/b/c',
			query:{
				id:data.xxx,
				title:'hello'
			}}">跳转</router-link>

	#取参数数据:
	$route.query.id
	$route.query.title

6.路由的params参数
	#配置路由,声明接收params参数
index.js	
	import VueRouter from 'vue-router'
	import A from '../pages/A'
	...
	export default new VueRouter(
	{
		path:'/a',
		component:A,
		children:[
			{
				path:'b',
				component:B
			},
			{
				component:Message,
				children:[
					{
						name:'cname',
						path:'c/:id/:title', //使用占位符声明接收params参数
						component:C
					}
				]
			}
		]
	})
	#传递参数	特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
【B】<!-- 跳转并携带params参数,to的字符串写法 -->
	<router-link :to="`/a/b/c/${data.id}/你好`">跳转</router-link>
					
	<!-- 跳转并携带params参数,to的对象写法 不能使用path配置项,必须使用name配置!-->
	<router-link 
		:to="{
			name:'cname',
			params:{
				id:data.id,
				title:'你好'
		}}">跳转</router-link>
	
	使用接收参数数据:
		$route.params.id
		$route.params.title
7.路由的props配置======================================================================================
	作用:让路由组件更方便的收到参数
index.js	
	import VueRouter from 'vue-router'
	import C from '../pages/C'
	...
	export default new VueRouter({
	routes:[{
		name:'cname',
		//path:'c/:id',
		path:'c',
		component:C,
		//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给C组件
		// props:{a:900}

		//第二种写法:props值为布尔值,若布尔值为true,则把路由收到的所有params参数通过props传给C组件
		// props:true
		
		//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给C组件【推荐】
		props($route){
			return {
				//id:$route.params.id,
				id:$route.query.id,
				title:$route.query.title
			}
		},
		//或者解构赋值写法:
		props({query:{id,title}}){
			return {id,title}
		}
	}
【X】
	//<router-link :to="`/c/${data.id}`">跳转</router-link>
	<router-link :to="{
				name:'cname',
				query:{
					id:data.id,
					title:data.title
					}}">{{data.title}}</router-link>
	
【C】
	声明接收数据,使用数据
		//props:['a']
		//this.a
		
		//props:['id']
		//this.id
		
		props:['id','title']
		this.id
		
8.<router-link>的replace属性========================================================================
	作用:控制路由跳转时操作浏览器历史记录的模式,历史记录是栈的结构,【默认router-link开启的是push模式,只管添加】
		replace模式是替换掉栈顶的那一条。
	浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
	开启replace模式:	
		<router-link :replace="true" >News</router-link>
		或者<router-link replace >News</router-link>
		
9.编程式路由导航 【路由器就是实现导航区跳转的】
	作用:不借助<router-link> 实现路由跳转,让路由跳转更加灵活
	this.$router.push()/.replace()
	使用:
		<button @click="methodName1(data1)">点我,展示区跳转到C组件</button>
		<button @click="methodName2(data2)">点我,展示区跳转到B组件</button>
		<button @click="methodName3">点我,根据历史记录栈前进</button>
		<button @click="methodName4">点我,根据历史记录栈后退</button>
【A】methood:{
		methodName1(data1){
			this.$router.push({//push方式推进
				name:'cname',
					params:{
						id:data1.id,
						title:xxx
					}
			})},
		methodName2(data2){
			this.$router.replace({//replace方式推进
				name:'bname',
					params:{
						id:data2.id,
						title:xxx
					}
			})},
		methodName3(){
			this.$router.forward()
		},
		methodName4(){
			this.$router.back()
		}
		
		this.$router.go() //历史记录栈可前进也可后退
			this.$router.go(-2)//向前走两步
			this.$router.go(+2)//向后走两步
			
10.缓存路由组件 【因为导航区路由组件被切换走之后会被销毁,所以原本填写的数据也会消失】
	<keep-alive include="组件名"> <keep-alive> 
	作用:让不展示的路由组件保持挂载,不被销毁。
【A】使用:
		<router-link active-class="active" to="/a/b">展示区展示B组件,就算切换走再切换回来,填写的数据也还在<router-link>
		<router-link active-class="active" to="/a/c">展示区展示C组件,现在换掉了B<router-link>

		<keep-alive include="B"> //想要缓存B组件
			<router-view></router-view>
		</keep-alive>
		或者
		<keep-alive :include="['B','C']"> //想要缓存B和C组件组件
			<router-view></router-view>
		</keep-alive>
		
11.两个新的生命周期钩子【路由组件独有】
	作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
	具体名字:
	activated(){}路由组件被激活时触发。即当前路由组件正在展示区展示
	deactivated(){}路由组件失活时触发。即当前路由组件被切换掉
	
12.路由守卫===================================================================================================
	作用:对路由进行权限控制,每次导航区切换组件,都会进行拦截和判断
	分类:全局守卫、独享守卫、组件内守卫
		全局守卫:每次导航区切换任意组件,都会进行拦截和判断,前置守卫调一次,后置守卫调一次
			router.beforeEach((to去哪里,from来自哪里,next放行)=>{})//全局前置守卫:全部路由初始化时执行、每次路由切换前执行
			router.afterEach((to去哪里,from来自哪里)=>{})//全局后置守卫:全部路由初始化时执行、每次路由切换后执行
		独享守卫:每次导航区切换指定组件,都会进行拦截和判断,独享守卫调一次
			routes:[{
				...
				beforeEnter(to,from,next)=>{}//独享守卫:配置在切换进入这个组件之前,进行的拦截和判断
			}]
		组件内守卫:每次导航区通过路由规则切换指定组件,都会进行拦截和判断,切换进来调Enter,被切换掉调Leave
			【C】  beforeRouteEnter (to, from, next) {xxx next()},
				   beforeRouteLeave (to, from, next) {xxx next()}
	
	可以使用this.$route.meta	来辅助进行守卫判断
index.js
	const router =  new VueRouter({
	routes:[
		{
		name:'aname',
		path:'/a',
		component:A,
		meta:{isAuth:true,title:'消息'},
		children:[
			{
				name:'bname',
				path:'b',
				component:B,
				meta:{isAuth:true,title:'xxx'},
				props($route){
					return {
						id:$route.query.id,
						title:$route.query.title,
						a:1,
						b:'hello'
					}
				}
//全局前置守卫:初始化时执行、每次路由切换前执行
	router.beforeEach((to,from,next)=>{
		console.log('beforeEach',to,from)
		//判断当前路由是否需要进行权限控制
		//if(to.path==='/a/b' || to.name==='bname'){ 
		if(to.meta.isAuth){ 
			if(localStorage.getItem('keyname') === 'value'){ //浏览器本地缓存存储WebStorage
				next() //放行
			}else{
				alert('暂无权限查看')
			}
		}else{
			next() //放行
		}
	})

//全局后置守卫:初始化时执行、每次路由切换后执行
	router.afterEach((to,from)=>{
		if(to.meta.title){ 
			document.title = to.meta.title //修改网页的title 记得将index.html里的title也改掉
		}else{
			document.title = 'yyy'
		}
	})
	
//独享守卫:配置在切换进入这个组件之前,进行的拦截和判断
index.js
	import VueRouter from 'vue-router'
	import A from '../pages/A'
	...
	const router =  new VueRouter({
		routes:[
			{
			name:'aname',
			path:'/a',
			component:A,
			meta:{title:'主页'},
			children:[
				{
				name:'bname',
				path:'b',
				component:B,
				meta:{isAuth:true,title:'新闻'},
				beforeEnter: (to, from, next) => {
					if(to.meta.isAuth){ //判断是否需要鉴权
						if(localStorage.getItem('keyname')==='value'){
							next()
						}else{
							alert('无权限查看!')
						}
					}else{
						next()
					}
				},
			}]}]


组件内守卫:===============================================================================
【C】	
	<script>
	export default {
		name:'About',
		...
		//进入守卫:通过路由规则,进入该组件时被调用
		beforeRouteEnter (to, from, next) {
		},
		//离开守卫:通过路由规则,离开该组件时被调用
		beforeRouteLeave (to, from, next) {
	}}</script>
	
13.路由器的两种工作模式
	对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
	hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
	hash模式:【默认】
		地址中永远带着#号,不美观 。
		若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
		兼容性较好。
	history模式:
		地址干净,美观 。
		兼容性和hash模式相比略差。
		应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
index.js
	import VueRouter from 'vue-router'
	import A from '../pages/A'
	...
	const router =  new VueRouter({
		mode:'history',
		...
	})

n、vue基础知识

/* 
简写形式:
	1、key与value重名,简写	a{bbb:bbb} => a{bbb}
	2、key为变量 value为函数,简写:
		a{
			b:function(){} => b(){}
		}
	3、对象中的key,本质都是字符串,所以加不加单引号都会被加上单引号,而value 如果不加单引号则被当作变量处理
	
字符串:<template>中使用双引号""作为字符串如果里面再嵌套字符串则用单引号'',
		<script>中使用单引号''作为字符串
		
模板字符串:``
	“原来只是被反撇号括起来的字符串啊”。模板字符串名之有理,它为JavaScript提供了简单的字符串插值功能,${}
	如果你需要在模板字符串中书写特殊字符,你必须使用反斜杠将其转义:`\`。
	模板字符串中所有的空格、新行、缩进,都会原样输出在生成的字符串中
	
v-bind:将字符串【除模板字符串】的内容当作在<script>定义过的变量来使用
*/
//Vue2响应式存在的问题:
	实现原理:
	- 对象类型:通过Object.defineProperty()对属性的读取、修改、拦截(数据劫持)。
	- 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
	- 存在问题:
	  - 新增属性、删除属性, 不是响应式的,界面不会更新。
	  - 直接通过下标修改数组, 界面不会自动更新。
	解决问题:
		1、新增对象属性用$set
		2、修改数组用封装好的数组方法 array.push('xxx','yyy') 末尾追加n个元素
							array.pop() 末尾删除一个元素
							array.shift() 删除第一个元素
							array.unshift('xxx','yyy') 头部增加n个元素
							array.splice(index,num,value) 【索引值 删除几个 添加的值为】
							array.sort()
							array.reverse()
		
/*$set向对象中添加一个响应式的属性
一般与hasOwnProperty一起使用,if(Obj.hasOwnProperty('propertyName'))
*/
	vm/this.$set( target, propertyName/index, value )
	或者import Vue from 'vue'
		Vue.set(target, propertyName/index, value)
	参数:
		{Object | Array} target
		{string | number} propertyName/index 属性名/数组索引下标
		{any} value
	返回值:设置的值。

//$delete对象中移除一个响应式的属性【很少使用】
	vm/this.$delete( target, propertyName/index )
		或者import Vue from 'vue'
			Vue.delete(target, propertyName/index)
		参数:
			{Object | Array} target
			{string | number} propertyName/index
		返回值:设置的值。



//$ref
	在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref 这个 attribute 为子组件赋予一个 ID 引用。例如:

	<base-input ref="usernameInput"></base-input>
	现在在你已经定义了这个 ref 的组件里,你可以使用:

	this.$refs.usernameInput
	来访问这个 <base-input> 实例

/*鼠标点击
	失去焦点 */
	<input type="text" @blur="method(params)">

//获取焦点
	<input v-show="false" ref="refName">
	<button @click="handleEdit(Obj)">编辑</button>
	
//$nextTick指定的函数会在dom解析完之后调用,避免input框v-show=false从而不显示函数运行效果【可用定时器代替】
	handleEdit(Obj){
				this.$nextTick(function(){
					this.$refs.refName.focus()
				})
			},
	setTimeout(()=>{//定时器就算立即到点,也会推向队列进行执行
		...
	},200)


//template 虚拟节点,页面只渲染其属性和内容,不渲染节点
//具名插槽与自定义标签体 插槽使用者向插槽传数据
指定插槽 slot="slotName"或template里用v-slot:slotName【推荐】=======================================================
【App 数据放在App里】
	   <A title="电影">
			<video v-slot:slotName1 controls src="http://xxx.mp4"></video>
			<template v-slot:slotName2>
				...
			</template>
	   </A>
【A】<template>
			<div class="a">
				<h3>{{title}}分类</h3>
				<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
				<slot name="slotName1">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
				<slot name="slotName2">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
			</div>
	 </template>
		
		props:['title']
//作用域插槽 插槽向插槽使用者传数据 必须用template,用scope或v-slot接收传输的数据封装为一个对象,
 【App】
	<A title="游戏">
		//<template scope="defReceiveObjName">
		<template v-slot:slotName1="defReceiveObjName">//Vue 2.6之后 v-slot:插槽名="组件内部绑定作用域值的映射"
			<ul>
				<li v-for="(g,index) in defReceiveObjName.games" :key="index">{{g}}</li>
			</ul>
		</template>
	</A>
 【A 数据放在A里】v-bind绑定data数据的,如果数据只是单纯的数据,就不用v-bind
	 <template>
		<div class="a">
			<slot name="slotName1" :games="games" msg="hello">我是默认的一些内容</slot>
		</div>
	</template>
	<script>
		export default {
			name:'A',
			data() {
				return {
					games:['...','...'],
				}
			},
		}
	</script>
============================================================================================


n+1、vue基础经验分享

/*
补充生命周期钩子函数:
	nextTick(){函数} 指定的函数会在dom解析完之后调用
	路由里还有
	activated(){}路由组件被激活时触发。即当前路由组件正在展示区展示
	deactivated(){}路由组件失活时触发。即当前路由组件被切换掉

import会引起句法检查,如果不想语法检查,可以在index.html中用link引入
import会在js文件全文扫描完后,按照import顺序优先进行执行,不管import之间有什么语句,都要后靠

data数据一改变,vue会重新解析模板;
	VueComponent不是直接存在的,是Vue.extend生成的,且每次调用Vue.extend时【<A/> <B>/】,返回的都是一个新的VueComponent
	VueComponent只要拥有props,就可以在模板中直接使用和vue.extend{}中this.使用;props的值不能改,指的是指向的对象地址不能改
	VueComponent与vm区别,有无el挂载,VueComponent.prototype.__proto__===Vue.prototype,可以让vc访问到Vue原型上的属性、方法

插值语法应用场景:{{}}里的数据只能来自于当前组件的data computed 或别的组件传来的props,不能来自于别的组件传来的事件$emit(event,params)
	要用的话只能用当前data的数据进行接收传参param,然后在事件绑定的方法methods中定义接收参数method(){this.param=params}方法。

computed:计算属性简写形式值可以读取,不可以改;如果使用的v-model绑定计算属性,则不能写成简写形式,v-model不能绑定props传过来的值
	v-model会根据当前input框type的类型发生变化

*/
//常用库文件
	animate.css
	bootstrap.css
	element-ui;antd【插件库】 
	connect-history-api-fallback 服务器文件,解决vue中用history模式打包上线后,404问题
=================================================================================
数据传输-组件间通信:
//1、父子组件之间传数据:
	#【P】 <S v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"></S>
	1、使用v-for时要同时绑定遍历每个元素的key值
	2、组件之间进行数据传递时,使用props进行接收 【P】:todo="todoObj"  【S】props:['todo'],

//兄弟组件之间传数据data:
	#【App】<A :add="ad"></A>
	#【App】<B :todos="datas"></B>
	1、传给共同的父亲 <App> 【A】props:['add'],Vue.extend{methods:{xxx(){this.add(data)} }
	【App】定义数据存储数组datas 和更改数据datas的函数ad() 
	【B】props:['todos'] <template><li v-for="() in todos"></template>

//2、自定义事件传数据
	【父组件】
	<S @eventame="methodName"></S>
	methodName(params){//添加一个todoObj对象
			this.datas.unshift(params)
		  }
	【子组件】
	methods:{
	add(){
	  this.$emit('eventame',params)
  
//3、全局事件总线:任意组件间通信【API中没有,是程序员经验,用的最多】
#1	安装全局事件总线:
		new Vue({
			......
			beforeCreate() {
				Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
			},
			......
		}) 

	使用事件总线:
	接收数据的组件:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
		最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。
		methods(){
		  demo(data){......}
		}
		......
		mounted() {
		  this.$bus.$on('xxxx',this.demo) //绑定事件
		}
	发送数据的组件:this.$bus.$emit('xxxx',数据)
#2 	数组/对象属性合并 this.ObjArr = {...this.ObjArr,...NewdataObj}
	会把两者不同的数据发送过来的新数据替换旧数据,保留新数据没有而旧数据有的属性值
	优点:写发送过来的数据时,属性不用按照对象定义顺序写,没有修改的属性可以不写
【发送组件】    methods:methodName(){
					this.$bus.$emit('eventName',{isLoading:true,errMsg:'',users:[],isFirst:false})
				}
【接受组件】	mounted() {
			this.$bus.$on('eventName',(NewdataObj)=>{
				this.ObjArr = {...this.ObjArr,...NewdataObj}
			})
		}

//4、消息订阅与发布
	安装pubsub:npm i pubsub-js

	引入: import pubsub from 'pubsub-js'

	接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
		最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。
		methods(){
		  demo(_,data){......}//第二个参数才是传递过来的数据,第一个参数是消息名,一般不用,用_占位就好
		}
		......
		mounted() {
		  this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
		}
	发送数据:pubsub.publish('xxx',data)

//5、Vuex插件,组件共享数据
//6、vue路由组件进行params参数或query参数传递。
=================================================================================
//方法都默认会有event事件作为参数,在调用时不必传实参,在定义方法时加上形参 
	常用的 e.target.value e.target.checked
//输入框接收数据进行数据存储:
	#<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
		可以 设置数据进行接收 title:''	,
		也可以add(event){console.log(event.target.value);//获取发生事件的dom元素的value
	
//返回一个不会重复的字符串:
	#import {nanoid} from 'nanoid' 
		nanoid();--- Math.random();---Data.now();

//复选框的不同勾选触发方式:
	#1、<input type="checkbox" :checked="xxx.completed【布尔值】" @change/@click="handleCheck(xxx.id)" />
		handleCheck(id){//勾选或取消勾选
			this.对象数组.forEach((item)=>{
			  if(item.id===id) item.completed=!item.completed
			})
		  }
	//组件间通信的话,一般会修改了props,所以不建议使用
	#2、<input type="checkbox" v-model="xxx.completed【布尔值】">	  

//自定义事件 通过this.$refs.refname.$on('eventname',回调)
	第二个参数:回调要么配置在methods中然后直接调用,要么用匿名箭头函数
	给谁绑定自定义事件,谁就要$emit,谁触发的自定义事件,this就是谁,不过如果this.method在本组件methods中有定义,优先用自己的method的
	【子】sendStudentlName(){
				//触发Student组件实例身上的atguigu事件
				this.$emit('eventname',params)
	【父】<Student ref="refname" @click.native="show"/>
			methods:{method(params){...}},
			mounted() {
					this.$refs.student.$on('eventname',this.method) //绑定自定义事件
				},

//修饰符================================================================================
//自定义组件绑定原生dom事件要加修饰符 .native ,否则会认为是自定义组件的自定义事件
	#<Student ref="student" @click.native="show"/>//不加native就把click当成自定义事件了【】Vue3.x 移除
//.number,绑定的数据强制转换为数字类型
		<select v-model.number="n">
		 <option value="1">1</option>或者不加修饰符,<option :value="1">1</option>
			...
		</select>
		data() {
			return {
				n:1, //用户选择的数字
			}
		},
//element-ui插件 使用:查看官方文档=======================================================================================
问题:若运行时显示缺少模块,not found 'xxx',解决:npm i xxx
	若Plugin/Preset files are not allowed to export objects 则babel.config.js
	"presets": [["es2015", { "modules": false }]],修改为==>"presets": [["@babel/preset-env", { "modules": false }]]
	或者修改为==> "presets": [["@babel/env", { "modules": false }]]



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值