Vue生命周期(钩子函数)、指令(表达式)、组件化(全局组件、局部组件、组件通信)

8. 生命周期钩子

_1. 生命周期

每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。

每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。

生命周期图示:

请添加图片描述请添加图片描述请添加图片描述

常用的生命周期方法
  • created()/mounted(): 发送 ajax 请求, 启动定时器等异步任务

  • beforeDestory(): 做收尾工作, 如: 清除定时器

示例
<template>
  <div class="demo1">
    <p><button type="button" @click="destroyVue">
销毁vue</button></p>
    <p>现在时间:{{now}}</p>
  </div>
</template>
<script>
export default {
  name: "demo1",
  data() {
      return {
      now: "",
      intervalId: ""
   };
 },
  methods: {
    destroyVue(){
      this.$destroy()
   }
 },
  created() {
    this.intervalId = setInterval(() => {
      let d = new Date();
      this.now = d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
      console.log(this.now);
   }, 1000);
 },
  beforeDestroy(){
    // 如果不清除定时器,vue实例销毁后定时器仍然会继续运行
    clearInterval(this.intervalId);
 }
};
</script>

_2. 钩子函数

可以在Vue中定义每个时期的构造函数,比如在刚才的案例中定义一个created函数,完成数据初始化

请添加图片描述

9. 指令

指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的预期值是: 单个 JavaScript 表达式 。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

_1. 差值表达式

 {{表达式}}
说明:
  • 该表达式支持JS语法,可以调用js内置函数(必须有返回值)

  • 表达式必须有返回结果。例如 1 + 1,没有结果的表达式不允许

    使用,如:var a = 1 + 1;

  • 可以直接获取Vue实例中定义的数据或函数

_2. v-model

v-textv-html可以看做是单向绑定,数据影响了视图渲染,但是反过来就不行。

v-model是双向绑定,视图(View)和模型(Model)之间会互相

影响。

v-model的可使用元素有:

  • input

  • select

  • textarea

  • checkbox

  • radio

  • components(Vue中的自定义组件)

基本上除了最后一项,其它都是表单的输入项

1 {{表达式}}

_3. v-on

v-on指令用于给页面元素绑定事件,可以用@简写

_3.1 基本语法

语法

v-on:事件名="js片段或函数名"

_3.2 事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

Vue.jsv-on 提供了 事件修饰符 。之前提过,修饰符是由开头的指令后缀来表示的。

  • .stop :阻止事件冒泡(注意一定要放在需要阻止冒泡的位置

    上)

  • .prevent:阻止默认事件发生

  • .capture:使用事件捕获模式

  • .self:只有元素自身触发事件才执行。(冒泡或捕获的都不执

    行)

  • .once:只执行一次

_3.3 按键修饰符

Vue 允许为v-on 在监听键盘事件时添加按键修饰符

 <input @keyup.enter="incr" v-model="num">
全部的按键别名:
  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

还可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘

事件的监听器。

  • .ctrl
  • .ctrl
  • .ctrl

例:

<!-- ctrl + C -->
<input @keyup.ctrl.67="copy">

_4. v-for

v-for用于循环遍历数据渲染页面

_4.1 遍历数组

<template>
  <div class="demo1">
    <ul>
        <!--
            语法:v-for="item in items"
            - items:要遍历的数组
            - item: 迭代得到的数组元素的别名
            - index:迭代得到当前元素的索引号
        -->
      <li  @click="getIndex(index)" v-for="(emp,index) in emps" :key="index">
        {{index+1}}-{{emp.name}}-{{emp.age}}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      emps:[
       {name:'张三', age: 25},
       {name:'李四', age: 26},
       {name:'王五', age: 27}
     ]
   }
 },
  methods:{
    getIndex(index){
      console.log(index);
   }
 }
};
</script>

更新参考

add(index){
    console.log(index);
    this.emps.splice(index+1,0,{name:'张三',age:50});
},
update(index){
 console.log(index);
 this.emps.splice(index,1,{name:'李四',age:28});
},
del(index){
 console.log(index);
 this.emps.splices(index,1);
}

_4.2 遍历对象

语法和遍历数组类似

v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
<template>
  <div class="demo1">
    <ul>
      <li v-for="(value,key,index) in emp">
        {{index}}-{{key}}-{{value}}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      emp:{
        name:'张三', sex:'男', age: 25, sal: 8000
     }
   }
 }
};
</script>

_5. v-if

基本语法

v-if="布尔表达式"
v-if-else="布尔表达式" // v-else-if 也必须紧跟在带
v-if 或者 v-else-if 的元素之后
v-else // v-else 元素必须紧跟在带 v-
if 或者 v-else-if 的元素之后

示例

<template>
  <div class="demo1">
    <button type="button" @click="toggle">
      <span v-if="isShow">隐藏</span>
      <span v-else>显示</span>
    </button>
    <h1 v-if="isShow">hello vue</h1>
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      isShow: true
   }
 },
  methods:{
    toggle(){
      this.isShow = !this.isShow;
   }
 }
};
</script>

_6. v-show

v-show用于根据条件展示元素,v-show只是简单地切换元素的 CSS 属性 display

<template>
  <div class="demo1">
    <button type="button" @click="toggle">
      <span v-show="!isShow">显示</span>
      <span v-show="isShow">隐藏</span>
    </button>
    <h1 v-show="isShow">hello vue</h1>
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      isShow: true
   }
 },
  methods:{
    toggle(){
      this.isShow = !this.isShow;
   }
 }
};
</script>

_7. v-bind

因为插值表达式不能用在属性的值中, 可以使用v-bind指令绑定class样式,v-bind指令可以简写为冒号:

示例- 1

<template>
  <div class="demo1">
    <div :class="divClass"></div>
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      divClass: "red"
   }
 }
};
</script>
<style scoped>
  .red{
    width:100px;
    height: 100px;
    background-color: red;
 }
</style>

示例- 2

注意这里的绑定值在{}中,red是样式名,isActive是布尔值,决定该样式是否显示

<template>
  <div class="demo1">
    <div :class="{red:isActive}"></div>
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      isActive: true
   }
 }
};
</script>
<style scoped>
  .red{
    width:100px;
    height: 100px;
    background-color: red;
 }
</style>

_8. 计算属性

使用计算属性可以替代复杂的表达式

示例- 1

使用计算属性前:

<template>
  <div class="demo1">
   今天是{{datetime.getFullYear()}}-
{{datetime.getMonth()+1}}-{{datetime.getDate()}}
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      datetime: new Date()
   }
 }
};
</script>

使用计算属性后:

<template>
  <div class="demo1">
   今天是{{getToday}}
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      datetime: new Date()
   }
 },
  computed:{
    getToday(){
      let d = this.datetime;
         return d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate();
   }
 }
};
</script>

示例- 2

计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter

<template>
  <div class="demo1">
    <p>FirstName:<input type="text" vmodel="firstName"></p>
    <p>LastName:<input type="text" vmodel="lastName"></p>
    <p>FullName:<input type="text" vmodel="fullName"></p>
  </div>
</template>
<script>
export default {
  name: "demo1",
  data(){
    return{
      firstName:"",
      lastName:""
   }
 },
  computed:{
    fullName:{
      get(){
        return this.firstName + " " + this.lastName;
     },
      set(val){
        let names = val.split(" ");
        this.firstName = names[0];
        this.lastName = names[1];
     }
   }
 }
};
</script>

_9. watch

watch用来监控一个值的变化,从而做出相应的反应

示例

<template>
  <div class="demo1">
    <input type="text" v-model="name">
  </div>
</template>
<script>
export default {
  name: "Demo1",
  data(){
    return{
      name:'张三疯'
   }
 },
  watch:{
    name(newVal,oldVal){
      console.log(oldVal + '改成了' + newVal)
   }
 }
};
</script>

_10. 表单输入绑定

<template>
  <div class="demo1">
    <form @submit.prevent="handleSubmit">
      <span>用户名:</span>
      <input type="text" v-model="user.username">
      <br>
      <span>密码:</span>
      <input type="password" v-model="user.pwd">
      <br>
      <span>性别:</span>
      <input type="radio" id="female" value="F" v-model="user.sex">
      <label for="female"></label>
      <input type="radio" id="male" value="M" vmodel="user.sex">
      <label for="male"></label>
      <br>
      <span>爱好:</span>
      <input type="checkbox" id="basket" value="basketball" v-model="user.hobby">
      <label for="basket">篮球</label>
      <input type="checkbox" id="foot" value="football" v-model="user.hobby">
      <label for="foot">足球</label>
      <input type="checkbox" id="pingpang" value="pingpang" v-model="user.hobby">
      <label for="pingpang">乒乓</label>
      <br>
      <span>城市:</span>
      <select v-model="user.cityId">
        <option value>未选择</option>
        <option v-for="city in allCitys" :key="city.id" :value="city.id">{{ city.name }}</option>
      </select>
      <br>
      <span>介绍:</span>
      <textarea v-model="user.desc" rows="10"></textarea>
      <br>
      <br>
      <input type="submit" value="注册">
    </form>
  </div>
</template>
<script>
export default {
  name: "demo1",
  data() {
    return {
      user: {
        username: "",
        pwd: "",
        sex: "F",
        hobby: [],
        cityId: "",
        desc: ""
     },
      allCitys: [
       { id: 1, name: "长沙" },
       { id: 2, name: "武汉" },
       { id: 3, name: "深圳" }
     ]
   };
 },
  methods: {
    handleSubmit(event) {
      alert(JSON.stringify(this.user));
   }
 }
};
</script>

10. 组件化

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展HTML 元素,封装可重用的代码

_1. 定义全局组件

示例

1. 创建组件相关目录及文件,参考

请添加图片描述

2. webpack首先会加载main.js,所以我们在main.js里面引入
import counter from './components/counter'
Vue.use(counter);	// 注入组件
3. 在Counter.vue里面定义自己的组件模板
<template>
  <div>
    <button type="button" @click="count++">点击次数{{ count }}</button>
  </div>
</template>
<script>
export default {
  name: "Counter.vue",
  data(){
    return{
      count:0
   }
 }
};
</script>
<style scoped></style>
4. 在counter/index.js文件里面添加install方法及导出组件
import myCounter from './Counter'
const Counter = {
  install(Vue){
    // 通过Vue的component方法来定义一个全局组件
    Vue.component('Counter',myCounter);
 }
}
// 导出组件
export default Counter;
5. 在其他组件中使用该组件
<template>
  <div class="demo1">
    <counter></counter>
    <counter></counter>
    <counter></counter>
  </div>
</template>
<script>
</script>
<style scoped>
</style>
6. 测试

请添加图片描述

_2. 局部组件

全局注册,就意味着即便你不使用这个组件,它依然会随着Vue的加载而加载。那么,对于一些并不频繁使用的组件,可以注册为局部组件。

局部组件只需要的地方直接引入,比如上例中,需要删除main.js中的相关代码,然后在Demo1.vue中直接引入

<template>
  <div class="demo1">
    <counter></counter>
    <counter></counter>
    <counter></counter>
  </div>
</template>
<script>
  import counter from './counter/Counter.vue';
  export  default {
    components:{counter}
 }
</script>
<style scoped>
</style>

_3. 组件通信

通常一个单页应用会以一棵嵌套的组件树的形式来组织

【X图片】
  • 页面首先分成了顶部导航、内容区、侧边栏三部分

  • 内容区又分为上下两个组件

  • 侧边栏中又包含了 3 个子组件

各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。

_3.1 父向子传递props

父组件使用子组件,同时传递属性

示例

  1. 创建组件Component1.vue

    <template>
      <div>{{ name }}是个好同志</div>
    </template>
    <script>
    export default {
      name: "Component1",
      props:['name']
    };
    </script>
    
  2. 父组件引用

    <template>
      <div class="demo1">
        <component1 name="张三疯"></component1>
      </div>
    </template>
    <script>
    import component1 from './Component1';
      export  default {
        components:{component1}
     }
    </script
    

_3.2 子向父通信

子组件接收到父组件属性后,默认是不允许修改的,所以对父组件属性的操作一定是放在父组件。

示例

  1. 创建组件Component2.vue

    <template>
      <div>
        <h1>{{num}}</h1>
        <button type="button" @click="add">+
    </button>
        <button type="button" @click="sub">-
    </button>
      </div>
    </template>
    <script>
    export default {
      name: "Component2",
      props: ["num"],
      methods: {
        add() {
          // this.$emit函数,用来调用父组件绑定的函数
          this.$emit('add');
       },
        sub() {
          this.$emit('sub');
       }
     }
    };
    </script>
    
  2. 父组件

    <template>
      <div class="demo1">
        <component2 :num="count" @add="incr"
    @sub="decr"></component2>
      </div>
    </template>
    <script>
    import component2 from "./Component2";
    export default {
      components: { component2 },
      data(){
        return{
          count: 50
       }
     },
      methods:{
        incr(){
          this.count++;
       },
        decr(){
          this.count--;
       }
     }
    };
    </script>
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值