目录
1、vue.config.js相关配置,代理服务器,vue-resource
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 }]]