首页 > 技术文章 > Vue框架的项目初始化,数据局部化处理,父子组件相互传递数据,路由的逻辑跳转,路由传参以及组件的生命周期钩子

jiangxianseng 2020-05-11 10:35 原文

Vue项目初始化

"""
1)根组件:App.vue
<template>
  <div id="app">
      <router-view />
  </div>
</template>

2)路由配置:router/index.js
const routes = [
  {
      path: '/',
      name: 'Home',
      component: Home
  }
];

3)组件:views和components文件夹
i)删除除Home.vue以为的所有组件
ii)初始化Home.vue
<template>
      <div class="home">
      </div>
  </template>

4)分类管理资源:assets文件夹
建立img、css、js子文件夹,删除原来的资源

5)如果要修改页面标签图标
替换public文件夹下的favicon.ico图片文件
"""

 

组件数据局部化处理

"""
1)不管页面组件还是小组件,都可能会被多次复用
2)复用组件的原因,其实就是复用组件的 页面结构、页面样式、页面逻辑
3)但是页面上的数据需要区分(被复用的两个组件数据多少是有区别的),所以组件的数据要做局部化处理
4)借助函数可以产生局部作用域的特点,为每一次复用组件产生一个独立的作用域
语法:
data () {
return {
// 数据们
}
}
"""
子组件
<template>
   <div class="beat" @click="count += 1">
       {{ count }}下
   </div>
</template>

<script>
   export default {
       name: "Beat",
       // 不管是页面组件还是小组件,都可能被复用,页面结构与样式都可以采用一套,但是数据一定要相互独立,借用函数的作用域,并且返回的也是字典
       data () {
           return {
               count: 0
          }
      }
  }
</script>

<style scoped>
   .beat {
       width: 100px;
       height: 100px;
       background-color: orange;
       text-align: center;
       line-height: 100px;
       border-radius: 50%;
  }
</style>
父组件
<template>
   <div class="home">
       <Beat/>
       <Beat/>
   </div>
</template>
<script>
   import Beat from '@/components/Beat'
   export default {
       components: {
           Beat,
      }
  }
</script>

 

方法和函数的区别

方法是有所属者的,要么是类调用,要么是对象调用

函数没有所属者,是由函数名调用的,由一个地址去访问代码块

路由逻辑跳转

"""
1)很多时候,我们需要通过普通按钮的逻辑,或是直接在某些逻辑中完成页面的跳转
2)可以通过在逻辑中用 this.$router.push() 来完成前往目标页,两种语法如下
this.$router.push('路径')
this.$router.push({name: '路由名'})
3)在做移动端项目时,没有像浏览器那样的前进后台键,页可以用 this.$router.go() 来完成前进后退,语法如下
前进后退:this.$router.go(正负整数),正式代表前进,负数代表后台,数值就是步长
"""
案例
<template>
   <div class="home">
       <Nav/>
       <h1>主页</h1>
       <button @click="goPage('/first')">前往第一页</button>
      |
       <button @click="goPage('/second')">前往第二页</button>
      |
       <button @click="goBack(-1)">后退一页</button>
      |
       <button @click="goBack(-2)">后退二页</button>
      |
       <button @click="goBack(1)">前进一页</button>
   </div>
</template>

<script>
   import Nav from '@/components/Nav'

   export default {
       methods: {
           goPage(path) {
               // 可以通过 this.$router 完成逻辑跳转,在任何一个组件内部都可以通过this来获取vue对象
               this.$router.push(); // $router['/','/first']里面存放的就是历史记录的列表数据
          },
           goBack(num) {
               // 一般在移动端项目上运用
               this.$router.go(num);  
          }
      },
       components: {
           
           Nav,
      }
  }
</script>

 

组件传参

父传子

一个页面组件是由许多小组间构成的,比如商品页面有许多商品,展示就是通过页面组件拿到数据并且传递给小组间,这就是父传子

"""
一、组件传参 - 父传子
1)在子组件内部通过props设置组件的自定义属性
  props: ['abc', 'goods']
2)在父组件渲染子组件是对自定义属性赋值即可
  <GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods"/>
"""
子组件
 <template>
   <div class="goods-box">
       <img :src="goods.img" alt="">
       <p>{{ goods.title }}</p>
   </div>
</template>

<script>
   export default {
       name: "GoodsBox",
       // 在子组件内部通过props定义组件的自定义属性,这个属性在父组件内被访问
       props: ['abc', 'goods'],
  }
</script>

<style scoped>
   .goods-box {
       width: 260px;
       height: 300px;
       border: 1px solid black;
       border-radius: 5px;
       margin: 20px;
       float: left;
       overflow: hidden;
       text-align: center;
  }
   img {
       width: 260px;
       height: 260px;
  }
</style>
父组件
<template>
   <div class="goods">
       <div class="main">
           <!-- 在使用子组件是对自定义属性赋值即可 -->
           <GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods" />
       </div>
   </div>
</template>
<script>
   import GoodsBox from "../components/GoodsBox";

   let goods_list = [
      {// 前端资源要用require处理一下
           img: require('@/assets/img/001.jpg'),
           title: '小猫',
      },
      {
           img: require('@/assets/img/002.jpg'),
           title: '小猫儿',
      },
      {
           img: require('@/assets/img/003.jpg'),
           title: '小狗',
      },
      {
           img: require('@/assets/img/004.jpg'),
           title: '小狗儿',
      },
  ];

   export default {
       name: "Goods",
       data () {
           return {
               goods_list,
          }
      },
       components: {
           GoodsBox,
      },
  }
</script>

 

子传父

"""
二、组件传参 - 子传父
前提:子组件是被父组件渲染的,所以子组件渲染要晚于父组件
1)子组件一定要满足一个条件,才能对父组件进行传参(某个时间节点 === 某个被激活的方法)
  eg:i)子组件刚刚加载成功,给父组件传参 ii)子组件某一个按钮被点击的时刻,给父组件传参 iii)子组件要被销毁了,给父组件传参
2)在子组件满足条件激活子组件的方法中,对父组件发生一个通知,并将数据携带处理(自定义组件事件),即告知父组件可以通过一个事件,比如receiveData接收数据,
  <div class="goods-box" @click="boxClick"></div>
  methods: {
      boxClick () { this.$emit('receiveData', this.goods.title, '第二个数据', '第三个数据') }
  }

3)在父组件渲染子组件时,为自定义事件绑定方法
  <GoodsBox @receiveData="recFn"/>

4)在父组件实现绑定方法时,就可 以拿到子组件传参的内容(接收到了通知并在父组件中相应)
  recFn(title, data2, data3) {
      console.log('接收到了' + title);
  }

组件标签不能绑定系统定义的事件,就像下面的例子一样,直接绑定点击事件会发生冲突因为这个GoodsBox标签是组件标签,代表了整个组件,内部有多个其他标签,会冲突,所以没有意义,子组件的事件都是在自己内部完成,可以降低组件的耦合度
<GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods" @click=""/>
"""
子组件
<template>
   <div class="goods-box" @click="boxClick">
       <img :src="goods.img" alt="">
       <p>{{ goods.title }}</p>
   </div>
</template>

<script>
   export default {
       props: ['abc', 'goods'],
       methods: {
           boxClick () {
               // 通知父级 - 自定义组件的事件
               this.$emit('receiveData', this.goods.title)
          }
      }
  }
</script>
父组件
<template>
   <div class="goods">
       <div class="main">
           <!-- 实现自定义事件,接收子组件通知的参数 -->
           <GoodsBox v-for="goods in goods_list" @receiveData="recFn"/>
       </div>
   </div>
</template>
<script>
   import GoodsBox from "../components/GoodsBox";
   export default {
       name: "Goods",
       data () {
           return {
               goodsTitle: '哪个',
          }
      },
       methods: {
           recFn(title) {
               console.log('接收到了' + title);
               this.goodsTitle = title;
          }
      },
       components: {
           GoodsBox,
      },
  }
</script>

补充:$表示什么意思

<template>
   <div class="goods-box" @click="boxClick">
       <img :src="goods.img" alt="">
       <p>{{ goods.title }}</p>
   </div>
</template>

<script>
   export default {
       props: ['abc', 'goods'],
       data(){
           return{
               a:1,
               data:2
          }
      }
       methods: {
           boxClick () {
               this.a  // 可以通过this直接访问到a
               this.$data.a         //也可以通过data来访问到a        
               this.data
               this.$data.data
          }
      }
  }
</script>
$就是vue在内部进行了一个处理,将属性格式化成$变量,目的是区别自己的变量,变成vue可以直接使用的变量

补充:js和vue的关系

vue是框架,内部的语法还是原生的js 语法,只是将js,css,html整合起来了变成一个组件

 

组件的生命周期钩子

"""
一、组件的生命周期:一个组件从创建到销毁的整个过程
二、生命周期钩子:在一个组件生命周期中,会有很多特殊的时间节点,且往往会在特定的时间节点完成一定的逻辑,特殊的事件节点可以绑定钩子
注:钩子 - 提前为某个事件绑定方法,当满足这个事件激活条件时,方法就会被调用 | 满足特点条件被回调的绑定方法就称之为钩子
"""
<template>
   <div class="goods">
       <Nav />
   </div>
</template>
<script>
   import Nav from "../components/Nav";
   export default {
       name: "Goods",
       components: {
           Nav,
      },
       beforeCreate() {
           console.log('该组件要被加载了')
      },
       created() {
           console.log('该组件要被加载成功了')
      },
       updated() {
           console.log('数据更新了')
      },
       destroyed() {
           console.log('该组件销毁了')
      }
  }
</script>

路由传参

"""
路由传参:
一、通过url正则传递数据
i)设置index.js
  路由: path: '/goods/detail/:pk'   |   '/goods/:pk/detail/:xyz'
  请求: '/goods/detail/任意字符'   |   '/goods/任意字符/detail/任意字符'
ii)如何传
  <router-link :to="`/goods/detail/${pk}`"></router-link>
  this.$router.push(`/goods/detail/${pk}`)

iii)如何取
  this.$route对象是管理路由参数的,传递的参数会在this.$route.params字典中
  this.$route.params.pk

二、通过url参数传递数据
i)设置
  路由: path: '/goods/detail'
  请求: '/goods/detail?pk=数据'
ii)如何传
  <router-link :to="`/goods/detail?pk=${pk}`"></router-link>
  <router-link :to="{name:'GoodsDetail', query:{pk: pk}}"></router-link>

  this.$router.push(`/goods/detail?pk=${pk}`)
  this.$router.push({name:'GoodsDetail', query:{pk: pk}})

iii)如何取
  this.$route对象是管理路由参数的,传递的参数会在this.$route.query字典中
  this.$route.query.pk
"""

第一种

配置:router/index.js
const routes = [
  {
       path: '/goods/detail/:pk',
       name: 'GoodsDetail',
       component: GoodsDetail
  },
]
传递:GoodsBox.vue
<router-link class="goods-box" :to="`/goods/detail/${goods.pk}`">
   <img :src="goods.img" alt="">
   <p>{{ goods.title }}</p>
</router-link>

<!------------------- 或者 ------------------->

<div class="goods-box" @click="goDetail(goods.pk)">
   <img :src="goods.img" alt="">
   <p>{{ goods.title }}</p>
</div>
<script>
   export default {
       name: "GoodsBox",
       methods: {
           goDetail (pk) {
               this.$router.push(`/goods/detail/${pk}`);
          }
      }
  }
</script>
接收:GoodsDetail.py
<script>
   export default {
       name: "GoodsDetail",
       data () {
           return {
               pk: '未知',
          }
      },
       // 通常都是在钩子中获取路由传递的参数
       created() {
           this.pk = this.$route.params.pk || this.$route.query.pk;
      }
  }
</script>

 

第二种

配置:router/index.js
const routes = [
  {
       path: '/goods/detail',
       name: 'GoodsDetail',
       component: GoodsDetail
  },
]
传递:GoodsBox.vue
<router-link class="goods-box" :to="`/goods/detail?pk=${goods.pk}`">
   <img :src="goods.img" alt="">
   <p>{{ goods.title }}</p>
</router-link>

<!------------------- 或者 ------------------->

<div class="goods-box" @click="goDetail(goods.pk)">
   <img :src="goods.img" alt="">
   <p>{{ goods.title }}</p>
</div>
<script>
   export default {
       name: "GoodsBox",
       methods: {
           goDetail (pk) {
               // this.$router.push(`/goods/detail?pk=${goods.pk}`);
               
               // 或者
               this.$router.push({
                   name: 'GoodsDetail',
                   query: {
                       pk,
                  }
              });
          }
      }
  }
</script>
接收:GoodsDetail.py
<script>
   export default {
       name: "GoodsDetail",
       data () {
           return {
               pk: '未知',
          }
      },
       // 通常都是在钩子中获取路由传递的参数
       created() {
           this.pk = this.$route.params.pk || this.$route.query.pk;
      }
  }
</script>

 

全局配置自定义css与js(src/assets下面的配置文件)

global.css
html, body {
   margin: 0;
}

a {
   color: black;
   text-decoration: none; //下划线
}

ul {
   margin: 0;
   padding: 0;
}
settings.js
export default {
   base_url: 'https://127.0.0.1:8000'
}
main.js
//1) 配置全局css
import '@/assets/css/global.css'
// import global_css from '@/assets/css/global.css' // 资源需要用变量保存,方便以后使用
// require('@/assets/css/global.css')
// let global_css = require('@/assets/css/global.css') // 资源需要用变量保存,方便以后使用


// 2) 配置自定义js设置文件
import settings from '@/assets/js/settings.js'
Vue.prototype.$settings = settings;
// 在任何一个组件中的逻辑,可以通过 this.$settings访问settings.js文件的{}数据

 

小结

"""
项目:
环境;node -> npm -> cnpm -> vue/cli
创建:vue create proj
配置:配置npm启动项
项目目录结构:依赖、环境、入口、核心代码们

组件:
构成:template + script + style
导入:import 别名 from '路径'
父加子:1)导入 2)注册 3)使用
组件数据:组件化处理 data(){ return {} }
传参:父传子 - 自定义组件属性 | 子传父 - 自定义组件事件
生命周期钩子:created() { //完成后台请求等 }

路由:
根组件中的页面占位:<router-view />
导航栏中的页面跳转:<router-link to=""></router-link>
代码中的逻辑跳转:this.$router.push() | this.$router.go()
路由传参:两种方式
两个路由对象:
this.$router - 控制路由跳转
      this.$route - 控制路由数据
"""

 

 

 

 

推荐阅读