【Vue】options构造选项(一)

727 阅读7分钟

vue实例(对象)

  • const vm = new Vue(options)根据options里的内容返回一个vue实例(对象)命名为vm
  • 把Vue的实例命名为vm是尤雨溪的习惯,我们应该沿用
  • 这个vm对象封装了对视图的所有操作,包括数据读写、事件绑定、DOM更新(注意,无Ajax)
  • vm的构造函数是Vue,按照ES6的说法,vm所属的类是Vue
  • options(一个对象)是new Vue的参数,一般称之为选项或构造选项(构造函数后面的选项)

组件

  • 组件被vue实例使用

  • 组件可以由一个vue文件生成,也可以我们声明一个组件(内容和options一模一样,除了data必须用函数)

  • 组件名开头大写

options的五类属性

数据

  • data 内部数据
  • props 外部数据,也叫属性
  • propsData 用不着学
  • computed 倍计算出来的
  • methods 面向对象的函数,也就是使用时要obj.sayHi()(普通函数sayHi()
  • watch

DOM

  • el 挂载点
  • template 在完整版里的视图
  • render 在非完整版里的视图,用不着学
  • renderError 在非完整版里的视图失败了

生命周期钩子:

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • activated
  • deactivated
  • beforeDestroy
  • destroyed
  • errorCaptured 先不看,用到再查文档

资源

  • directives 指令
  • filters 过滤器(不要用了),用methods代替
  • components 组件,如Demo.vue

组合

  • parent 先不看,用到再查文档
  • mixins 混入
  • extends 扩展
  • provide
  • inject 注入

其他

先不看,用到再查文档

el--挂载点

你的组件、你的实例的挂载点。

  1. 两个用法
new Vue({
  el: "#app"
});

new Vue({}).$mount('#app')
  1. 被你选为挂载点的那个元素,如果在index.html里那个元素里面本来就有内容,在渲染时会消失,被这个vue实例的对应内容所覆盖。除非你网速慢,js还没加载好。

data -- 内部数据

  1. 两个用法:对象和函数(函数里返回对象就行了),优先使用函数
new Vue({
  data() {
    return {
      n: 0,
      array:[1,2,3]
    }
  }
}).$mount("#app");
  1. 有bug,在数据响应式时在了解

methods -方法

  1. 两个用法
  • 事件处理函数
  • 普通函数(直接在视图里调用,每一次更新渲染都会调用一次)
import Vue from "vue";
Vue.config.productionTip = false;

new Vue({
  data() {
    return {
      n: 0,
      array: [1, 2, 3, 4, 5, 6, 7, 8]
    };
  },
  template: `
  <div class=red>
  {{n}}
  <button @click="add">+1</button>  //事件处理函数
  <hr>
  {{filter()}}   //普通函数(直接在视图里调用,每一次更新渲染都会调用一次)
  </div>
  `,
  methods: {
    add() {
      this.n += 1;  //事件处理函数
    },
    filter() {
      return this.array.filter(i => i % 2 === 0);  //普通函数
    }
  }
}).$mount("#app");

components--Vue组件

注意大小写 三种引入方式,推荐最后一种

方法一:推荐使用,很模块化

  1. 新建一个vue文件Demo.vue,这个vue文件就是一个组件
  2. 在main.js中引入这个vue文件
  3. 在vue实例的components中声明这是我要用的组件,并且命名为Demo1
  4. 这样在这个Vue实例的template中就可以直接使用这个组件<Demo1/>
import Vue from "vue";
import Demo from "./Demo.vue";  //引入这个vue文件
Vue.config.productionTip = false;

new Vue({
  components: {
    Demo1: Demo  //在vue实例的components中声明这是我要用的组件,并且命名为Demo1
    //如果组件名就叫Demo,即Demo:Demo,那就写Demo
    //components: {Demo},
  },
  data() {
    return {
      n: 0
    };
  },
  template: `
  <div class=red>
  {{n}}
  <button @click="add">+1</button>
  <Demo1/>   //这样在这个Vue实例的template中就可以直接使用这个组件`<Demo1/>`
  </div>
  `,
  methods: {
    add() {
      this.n += 1;
    },
  }
}).$mount("#app");

方法二:全局

  1. 在main.js里直接写一个全局组件,写组件名字和内容(内容和options一模一样,除了data必须用函数)
  2. 直接在任何Vue实例的template中就可以使用这个组件<Demo2/>
import Vue from "vue";
Vue.config.productionTip = false;

Vue.components('Demo2,{template:`<div>Demo2</div>`}') //在main.js里直接写一个全局组件,写组件名字和内容
new Vue({
  data() {
    return {
      n: 0
    };
  },
  template: `
  <div class=red>
  {{n}}
  <button @click="add">+1</button>
  <Demo2/>   //直接在任何Vue实例的template中就可以使用这个组件`<Demo2/>`
  </div>
  `,
  methods: {
    add() {
      this.n += 1;
    }
  }
}).$mount("#app");

方法三:上面结合

在vue实例的components中写这个vue实例要用的组件,组件名为Demo3,内容为和options一模一样,除了data必须用函数

import Vue from "vue";
Vue.config.productionTip = false;

new Vue({
  components: {
    Demo3: { template: `<div>Demo2</div>` }  //在vue实例的components中写这个vue实例要用的组件,组件名为Demo3,内容和options一模一样,除了data必须用函数
  },
  data() {
    return {
      n: 0
    };
  },
  template: `
  <div class=red>
  {{n}}
  <button @click="add">+1</button>
  <Demo3/>   //直接在这个Vue实例的template中就可以使用这个组件`<Demo3/>`
  </div>
  `,
  methods: {
    add() {
      this.n += 1;
    }
  }
}).$mount("#app");

四个钩子

  1. created -- 实例出现在内存中后触发
  2. mounted-- 实例出现在页面中(挂载了)后触发
  3. updated -- 实例更新了后触发
  4. destroyed -- 实例从页面和内存中消亡了后触发

props-外部数据、属性

  • message="n"传入字符串
  • :message="n"传入vue实例的this.n数据
  • :fn="add"传入vue实例的this.add函数

我是一个组件,我的props指 属性名是我定义在我自己里面,我的template也用到了这些属性,但是属性值是从外面传给我的

(所以我自己不能改这个属性值的,属性值是从外面来的,所以我自己就算改了,外面的改了之后我的属性值还是得跟着外面的来。我就是想要修改!请看最下面)

外面咋传给我?外面的Vue实例在引用我这个组件的时候传给我。

在Demo.vue组件里

<template>
  <div class="red">
    这是Demo内部
    {{message}} //我要用message
    <button @click="fn">点我</button> //我要用fn
  </div>
</template>

<script>
export default {
  props: ["message", "fn"] 
  //表示本组件可以接受一个参数message和fn,但是message和fn的值不是从我这里传入的,是外面传给我的。
  //所以message和fn就是Demo的外部数据(属性名是我定义在我自己里面,我的template也用到了这些属性,但是属性值是从外面传给我的)
};
</script>

<style scoped>
.red{
    color: :red;
}
</style>

在main.js里

import Vue from "vue";
import Demo from "./Demo.vue";
Vue.config.productionTip = false;

new Vue({
  components: { Demo },
  data() {
    return { n: 0 };
  },
  template: `
    <div>
      <Demo message="n"/>      //在引用Demo组件时把他要用的message的值传入,值就为一个字符串n
      <Demo :message="n"/>      //在引用Demo组件时把他要用的message的值传入,值为这个Vue实例的data里的n
      <Demo :fn="f1"/>        //在引用Demo组件时把他要用的fn的值传入,值为这个Vue实例的methods里的f1
      </div>
  `,
  methods: {
    f1() {
      console.log("Hi");
    }
  }
}).$mount("#app");

例子(非完整版Vue)

代码

  1. 组件不可以修改props!!!外部给组件的,你怎么说修改就修改?

  2. 我(组件)就是想要改我的一个props:money,也就是外部(父组件)给我total

  3. 可以!你通知外部你想咋改,外部来改,你不也就同时被改了吗

  4. 怎么通知?eventBus!但在Vue里面是

  • 儿子用$emit触发updata-xxx事件,同时还得传参数,参数是儿子想怎么对自己的外部数据的操作);

    <button @click="$emit('update:money', money-100)">

  • 爸爸在引用儿子的时候用v-on监听updata-xxx事件,他的事件处理函数会自动有那个参数,为可以用$event获得那个参数,因为爸爸是把自己的total赋值给儿子的外部数据的。所以事件处理函数就为把参数给自己的total。(儿子想怎么操作自己的外部数据,爸爸本来是把自己的total给儿子的外部数据的。那么爸爸(通过监听updata:money事件和$event)知道儿子想怎么操作他自己的外部数据,爸爸就让自己的total等于儿子的操作就行了。)

    <Child :money="total" v-on:updata:money="total= $event"/>

    注意,完全等同于<Child :money.sync="total"/>(同步)(语法糖)

  1. 儿子想咋改,写在$emit的第二个参数里;爸爸就会从v-on里用$event获取$emit的那个参数就知道儿子是想咋改的,爸爸就会把这个结果给自己的total。

  2. 爸爸的total改了,儿子的money不就给改了??!!成功

写一个(子)组件Child.vue

<template>
  <div class="child">
    {{money}}          //儿子这里要显示钱
    <button @click="$emit('update:money', money-100)">  
    //儿子每次点击按钮就是想花钱,可是钱是爸爸给的自己花不了。
    //那就每次花钱的时候触发花钱事件update:money,这个事件会把爸爸给的钱-100,也就是儿子想怎么把这个钱花掉
      <span>花钱</span>
    </button>
  </div>
</template>

<script>
export default {
  props: ["money"]  //儿子需要父亲给钱money
};
</script>


<style>
.child {
  border: 3px solid green;
}
</style>

写一个(父)组件App.vue ,这就是非完整版要用的vue文件

<template>
  <div class="app">
    App.vue 我现在有 {{total}}
    <hr>
    <Child :money="total"  v-on:updata:money="total= $event"/>
    //爸爸在引用儿子的时候,先把自己的钱total给儿子money,在监听儿子的花钱事件updata:money,只要儿子花钱了,就把自己现在的钱total的金额=儿子想怎么花掉这钱$event。爸爸的total变了,儿子的money也变了
    //爸爸把total给儿子当他的money,要是儿子想改money就通知爸爸改爸爸的total
  </div>
</template>

<script>
import Child from "./Child.vue";
export default {
  data() {
    return { total: 10000 };
  },
  components: { Child: Child }
};
</script>

<style>
.app {
  border: 3px solid red;
  padding: 10px;
}
</style>

总结:vue的修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定的。sync是个语法糖。他是尤雨溪为我们写的<Child :money="total" v-on:updata:money="total= $event"/>的简写形式。

  • 子组件的外部数据是xxx ,父组件把自己的yyy给子组件当xxx的值。子组件想修改自己的外部数据xxx,只需要在某个时刻this.$emit('updata:xxx',想咋改),父组件:xxx.sync='yyy'就行了(父组件首先把自己的yyy给子组件当xxx,之后如果想改父组件会把自己的yyy改了)

通信

目的:父组件想要子组件的信息

做法

  1. 首先,父组件在使用子组件时要监听一个事件,事件处理函数中会自动有个参数就是父组件想要的信息,这样我们就可以对信息进行操作
<template>
    <Tags @updata:tags="onUpdateTags"/>
</template>

<script>
   onUpdateTags(selectedTags: string[]) {
      console.log(selectedTags);
    }
<script/>
  1. 其次,子组件需要在某个时刻触发这个事件,同时必须把父组件想要的自己的信息当第二个参数。

this.$emit("updata:tags",this.selectedTags)

  1. 那么,子组件触发这个事件,父组件监听到了,信息也传过来了,父组件里的事件处理函数开始执行了----父组件就可以对信息操作了

例子---子组件想要修改自己的props

描述

  • 子组件想要修改自己的props:money的值,不能,因为props:money的值是父组件把自己的total传给子组件的。
  • 所以可以用通信。让父组件知道子组件想怎么样修改props:money的值,父组件改自己的total不就好了

步骤

  • 因为子组件是想点击按钮时想让props:money的值减掉100,所以在点击按钮时$emit触发updata:money事件,同时因为父组件想知道子组件是怎么修改的,所以把这个信息作为第二个参数

    <button @click="$emit('update:money', money-100)">

  • 那么父组件在使用子组件时,监听updata:money事件,事件处理函数中有个参数$event就是信息,把信息给total就行了

  • <Child :money="total" v-on:updata:money="total= $event"/>

  • 那么,子组件点击按钮会触发updata:money事件,父组件监听到了,怎么修改money信息也传过来了,监听函数执行了,就可以把这个信息给total了,那么money的值不也被修改了吗!