vue基础知识总结(附实例)


vue 基础知识部分

构造器

  • 实例化 vue 时,需传入一个选项对象,它可以包括 数据、模板、挂载元素、方法和生命周期钩子

属性与方法

  • 每个 vue 实例都会代理其 data 对象里所有的属性
  • vue 实例暴露了一些有用的实例属性与方法,这些属性与方法都有前缀$,以便与代理的 data 属性区分

实例生命周期

  • created 钩子——在实例被创建后被调用
  • mounted—-当编译好的 HTML 被挂载到对应的位置,这个操作完成后触发
  • updated—-当 data 中的数据改变,并且虚拟 DOM 重新渲染完成后触发
  • destroyed
  • 概要: 钩子的 this 指向调用它的实例

生命周期图示

生命周期

生命周期钩子(11个) 解释
beforeCreate 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer), 属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
breforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
activated keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。
deavtivated keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
errorCaptured(2.5.0+ 新增) 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

注意 mounted、updated不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用vm.$nextTick 替换掉mounted、updated:

updated: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been re-rendered
  })
}

插值

  • 文本
    • 双大括号
    • v-text
  • 纯 HTML
    • v-html
  • 属性
    • v-bind(大双括号不能在属性中使用,因此需使用 v-bind)
  • 使用 JavaScript 表达式

指令

  • 哪些指令?

    • v-bind
    • v-on
    • v-if
    • v-for(特殊)

v-if

<div id="app">
 <template v-if="ok==='username'">
 用户名: <input type="text" placeholder="请输入用户名" key="name-input">
 </template>
 <template v-else>
密码: <input type="text"  placeholder="请输入密码" key="psd-input">
 </template>
 <button @click="toggle">点击切换类型</button>
</div>
new Vue({
  el: "#app",
  data: {
    ok: "username"
  },
  methods: {
    toggle: function(todo) {
      if (this.ok === "username") {
        this.ok = "psd";
      } else {
        this.ok = "username";
      }
    }
  }
});

v-for

<div id="app">
 <ul>
   <li v-for="item in items">{{item}}</li>
 </ul>
</div>
new Vue({
  el: "#app",
  data: {
    items: ["a", "b", "c"]
  },
  methods: {
    toggle: function(todo) {
      todo.done = !todo.done;
    }
  }
});

修饰符

  • v-on
  • .stop 阻止单击事件冒泡 <a v-on:click.stop="doThis"></a>
  • .prevent 提交事件不再重载页面
  • .capture 添加事件侦听器时使用时间捕获模式
  • .self 只当事件在该元素本身(而不是子元素)触发时触发回调

过滤器

  • 过滤器的目的是用于文本转换,转化成你想要的格式,还是给大家来个例子

filters

<div id="app">
  <p>{{message | changeChar}}</p>
  <button @click="changeFirstChar">改变</button>
</div>
new Vue({
  el: "#app",
  data: {
    message: "nihao"
  },
  methods: {
    changeFirstChar: function(todo) {
      this.message = "good evening";
    }
  },
  filters: {
    changeChar(value) {
      if (!value) {
        return "";
      } else {
        return value.charAt(0).toUpperCase() + value.substring(1);
      }
    }
  }
});

缩写

  • v-bind 缩写
    • 原有: <a v-bind:href="url"></a> 缩写: <a :href="url"></a>
  • v-on 缩写
    • 原有:<button v-on:click="doSomeThing"></button> 缩写:<button @click="doSomeThing"></button>

计算属性

计算属性(减少模板的复杂度)

  • 基础例子 1
  • 计算属性的两种写法

computed

<div id="app">
   {{fullName}}
</div>
new Vue({
  el: "#app",
  data: {
    firstName: "hello",
    lastName: "world"
  },
  computed: {
    fullName() {
      return this.firstName + "----" + this.lastName;
    }
  }
});
  • 计算缓存 vs 方法(Methods)

    • 计算属性 computed 具有缓存,而 methods 无缓存
  • Computed 属性 vs 侦听器(Watch 属性)

    • watch 方法–观察 Vue 实例上的数据变动,只要指定的数据改变就会执行预定的函数

watch

<div id="app">
    {{msg}} <br>
    改变了吗? {{isChange}}
    <button @click="change">改变</button>
</div>
new Vue({
  el: "#app",
  data: {
    msg: "欲穷千里目",
    isChange: "No"
  },
  watch: {
    //只要msg改变,这个方法就会执行
    msg(val, oldVal) {
      this.isChange = "Yes";
    }
  },
  methods: {
    //不得不说ES6写起来真爽
    change() {
      this.msg = "更上一层楼";
    }
  }
});
  • computed 方法

  • 计算 setter 和 getter * get 和 set,顾名思义,一个是获得,一个是设置,常规上来讲,计算属性中都是有 get 和 set 方法的,默认是只有 getter 方法,如果需要的话,自然,你也可以写一个 setter 方法.来个例子,诸位往下看:

get 和 set

<div id="app">
此时的onpiece: {{onepiece}} <br>
此时的msg:  {{msg}} <br><br>
<button @click="setName">设置name</button>
</div>
new Vue({
  el: "#app",
  data: {
    name: "Kobe",
    msg: ""
  },
  methods: {
    setName() {
      this.onepiece = "JorDan";
    }
  },
  computed: {
    onepiece: {
      get() {
        return this.name + "Bryant";
      },
      set(newVal) {
        //当你给 onepiece 设置值的时候 set 就就会调用
        this.msg = newVal + "is the greatest basketball player";
      }
    }
  }
});

class 与 style 绑定

绑定 HTML class

  • 对象语法

  • 基本

  • 在对象中传入多个 class 属性(其会与原有 class 共存)

  • 直接传入对象

  • 与计算属性一起使用(绑定返回对象的计算属性)

  • 数组语法

  • 简单例子

  • 三元表达式

  • 当有多个条件 class 时,可以在数组语法中使用对象语法

  • 用在组件上

  • 简单例子

  • 绑定 HTML class 例子

.classC {
  color: red;
}
.classD {
  font-weight: bold;
}
.classE {
  font-size: 20px;
}
.classF {
  color: blue;
}
.classM {
  display: block;
}
.classN {
  display: none;
}
<div id="app">
 <h2>class属性绑定</h2>
-------------------绑定变量-------------------------
<div :class="{classA:a,classB:b}">
  绑定变量
</div>
 -------------------绑定对象-------------------------
<div :class="styleObj">
  绑定对象
</div>
 -------------------绑定数组-------------------------
<div :class="arrClass">
  绑定数组
</div>
  -------------------绑定三元运算符-------------------------
<div :class="m==true?'classM':'classN'">
  绑定变量
</div>
  <button @click="toggle">toggle</button>
</div>
new Vue({
  el: "#app",
  data: {
    a: true,
    b: false,
    styleObj: {
      classC: true,
      classD: true
    },
    m: true,
    arrClass: ["classE", "classF"]
  },
  methods: {
    toggle() {
      this.m = !this.m;
    }
  }
});

绑定内联样式

  • 对象语法
    • 内联式对象语法
    • 样式对象式对象语法(更推荐)
  • 数组语法
  • 自动添加前缀
    • v-bind:style 当需要特定的前缀时如 transform,vue.js 会自动添加
  • 多重值 * 从 vue2.3+后,可以为一个属性添加多个值的数组,常用于含有多个前缀的情况
    例子跟上边差不了多少,懒得写了.相信大家应该也都会,哈哈哈哈~

条件渲染

v-if(v-else)是真正的渲染

  • template 元素与 v-if

  • v-else(需要紧跟在 v-if 后边)

  • v-else-if(vue2.1.0 新增)

  • 用 key 管理可复用的元素—(如果这个例子看不懂的话.可以在群里问我!!!)

    • 例子:用户名和邮箱登录界面 如果有 key 就不会复用,大家可以把 key 去试一下,然后输入看一下效果!!!
<div id="app">
  <template v-if="ok==='username'">
      用户名: <input type="text" placeholder="请输入用户名" key="name-input">
  </template>
  <template v-else>
      密码: <input type="text"  placeholder="请输入密码" key="psd-input">
  </template>
  <button @click="toggle">点击切换类型</button>
</div>
new Vue({
  el: "#app",
  data: {
    ok: "username"
  },
  methods: {
    toggle: function(todo) {
      if (this.ok === "username") {
        this.ok = "psd";
      } else {
        this.ok = "username";
      }
    }
  }
});

v-show(其只是简单的切换 display 属性)

  • v-show 不支持 template 语法
  • v-show 不支持 v-else

v-if VS v-show

  • v-if
    • 当条件不成立时不会渲染
    • 切换开销较大,适合不太可能变化的场景
  • v-show
    • 无论成不成立都会渲染
    • 首次渲染开销较大,但切换开销小,因此适合经常变化的场景

列表渲染

v-for

  • 基本用法
    • 简单例子
    • 带有 index 参数
    • 使用 of 替代 in
  • template v-for
    • 简单例子
  • 对象迭代 v-for
    • 基础用法
    • 带其他参数用法
  • 整数迭代 v-for
    • 例子
  • 组件和 v-for
    包含所有类型的例子
<div id="app">
  <hr>
  <strong style="border:2px solid #ccc;">遍历数组:</strong>
  <ul>
    <li v-for="item in items" >{{item}}</li>
  </ul>
    <hr>
  <strong style="border:2px solid #ccc;">遍历对象数组:</strong>
  <ul>
    <li v-for="(item,index) in pers">{{index}}--我是{{item.name}},今年{{item.age}}岁</li>
  </ul>
      <hr>
  <strong style="border:2px solid #ccc;">遍历对象:</strong>
  <ul>
    <li v-for="(value,key) in obj">
      key:{{key}} |
      value:{{value}}
    </li>
  </ul>
</div>
new Vue({
  el: "#app",
  data: {
    isOK: "true",
    items: ["香蕉", "苹果", "烤肉"],
    pers: [
      {
        name: "Kobe",
        age: "40"
      },
      {
        name: "James",
        age: "38"
      }
    ],
    obj: {
      1: "one",
      2: "two"
    }
  }
});

key

  • 作用

    • 用 v-for 更新已渲染过的列表时,它默认采用的是“就地复用”的原则,也就是如果数据项顺序发生了改变,vue 将不是移动 DOM 元素来匹配数据项的顺序,而是简单复用此处的元素。如果想跟踪每个节点的身份,从而重用或重新排列现有元素,可使用 key。(key 还可用在 v-if 中,详见 v-if 中的邮箱名和用户名切换的例子)
  • 好吧,可能大家看到这里是一头雾水,不知所以,忧心忡忡,到底 key 有什么卵用,刚才上边的例子不是没有加 key 吗?好吧,不扯那没用的,通过一个例子告诉大家 key 到底有啥用!!!

<div id="app">
  KEY: <input type="text" v-model="id"> VALUE: <input type="text" v-model="name">
  <button @click="add">添加</button>
  <ul>
    <li v-for="item in list" :key="item.id">
    <!--此处你可以吧key去了,先勾选一条,在追加一条试一下,然后加上key,勾选一条追加一条再试一下,一目了然-->
      <input type="checkbox" >
      {{item.id}}---{{item.name}}
    </li>
  </ul>
</div>
new Vue({
  el: "#app",
  data: {
    id: "",
    name: "",
    list: [
      { id: 1, name: "李斯" },
      { id: 2, name: "嬴政" },
      { id: 3, name: "赵高" },
      { id: 4, name: "韩非" },
      { id: 5, name: "荀子" }
    ]
  },
  methods: {
    add: function() {
      this.list.unshift({ id: this.id, name: this.name });
    }
  }
});

因为加上 key 默认采取的就是就地复用策略,这个例子,如果不懂,可以在群里问我

数组更新检测

  • 变异方法(会改变原有数组)
    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()
  • 重塑数组
    • filter()
    • concat()
    • slice()
  • 注意事项
    利用索引直接设置一个项时,vue 不能检测变动,如: vm.items[indexOfItem] = newValue
    那如果设置某一项的该怎么设置呢?
    _ Vue.set(example1.items, indexOfItem, newValue)
    _ example1.items.splice(indexOfItem, 1, newValue)
<div id="app">
  <button @click="setZF">设置第二项为张飞</button>
  <button @click="setGY">设置第三项为关羽</button>
  <ul>
    <li v-for="item in list">
      <input type="checkbox" >
      {{item.id}}---{{item.name}}
    </li>
  </ul>
</div>
var vm = new Vue({
  el: "#app",
  data: {
    id: "",
    name: "",
    list: [
      { id: 1, name: "李斯" },
      { id: 2, name: "嬴政" },
      { id: 3, name: "赵高" },
      { id: 4, name: "韩非" },
      { id: 5, name: "荀子" }
    ]
  },
  methods: {
    setZF: function() {
      Vue.set(this.list, 1, { id: 2, name: "张飞" });
    },
    setGY: function() {
      this.list.splice(2, 1, { id: 3, name: "关羽" });
    }
  }
});
* 修改数组长度时,vue不能检测变动,如:vm.items.length = newLength
* 只能用example1.items.splice(newLength)

对与显示过滤/排序结果的两种方法

  • 过滤数组–计算属性 computed 例子

  • 过滤数组–方法 methods 例子

计算属性应用于过滤

<div id="app">
  {{specialNum}}
</div>
new Vue({
  el: "#app",
  data: {
    nums: [1, 2, 3, 4, 5, 6, 7, 8, 9]
  },
  computed: {
    specialNum() {
      return this.nums.filter((item, index) => {
        return item % 3 == 0;
      });
    }
  }
});
<div id="app">
  <ul>
  在v-for循环中直接嵌入方法
    <li v-for="item in fil(numbers)">{{item}}</li>
  </ul>
</div>
new Vue({
  el: "#app",
  data: {
    numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9]
  },
  methods: {
    fil(nums) {
      return nums.filter((item, index) => {
        return item % 3 == 0;
      });
    }
  }
});

两个简单的事件处理器

先来一个简单小李子,v-on 用来绑定事件

1

<div id="app">
 <button @click="num+=1">增加1</button>
 {{num}}
</div>

2

<div id="app">
  <button @click="sayHello">点击sayHello</button>
</div>
new Vue({
  el: "#app",
  methods: {
    sayHello: function() {
      alert("sayHello");
    }
  }
});

内联处理器方法

  • 访问原生 DOM 事件的例子,如果 click 事件不传参数,就默认把原生 DOM 传递进去
<div id="app"> //没有传参数,就是原生的!!!
<button @click="showBtnname">显示按钮的名字</button> <br><br>
  {{msg}}
</div>
new Vue({
  el: "#app",
  data: {
    msg: ""
  },
  methods: {
    showBtnname: function(e) {
      this.msg = e.target.innerText;
    }
  }
});
  • 未访问原生 DOM 事件的例子,如果传了参数.那么方法中接受的第一个参数就是该参数,在 vue 中所有的事件绑定都是这样的
<div id="app">
  <h2>Todos:</h2>
  <ol>
    <li v-for="todo in todos">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }}
        </span>
      </label>
    </li>
  </ol>
</div>
new Vue({
  el: "#app",
  data: {
    todos: [
      { text: "Learn JavaScript", done: false },
      { text: "Learn Vue", done: false },
      { text: "Play around in JSFiddle", done: true },
      { text: "Build something awesome", done: true }
    ]
  },
  methods: {
    toggle: function(todo) {
      todo.done = !todo.done;
    }
  }
});
body {
  background: #20262e;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}

事件修饰符

  • .stop
    • 阻止单击事件冒泡
  • .prevent
    • 提交事件不再重载页面
  • .capture
    • 使用事件捕获模式
  • .self
    • 只有当事件在该元素本身被触发时(不包含子元素)才触发回调
  • .once
    • 事件只触发一次(vue 2.1.4 新增)
  • 修饰符串联
    • 例子

按键修饰符

  • .enter

    • keyCode
    • .enter
  • .tab

  • .delete

    • (捕获 “删除” 和 “退格” 键)
  • .esc

  • .space

  • .up

  • .down

  • .left

  • .right

  • 组合使用,单独是使用的话,和 click 都是一样的,这里组合使用有点特殊,使用 . 进行连接简单给个例子

<div id="app">
<button @click.ctrl="num++">num+1</button>
{{num}}
</div>
new Vue({
  el: "#app",
  data: {
    num: 0
  }
});

vue2.1.0 新增 按键修饰符

  • .ctrl
  • .alt
  • .shift
  • .meta

表单控件绑定

基础用法

  • 文本
<div id="app">
  <h2>{{msg}}</h2>
  <br>
  <input type="text" v-model="msg">
</div>
new Vue({
  el: "#app",
  data: {
    msg: "万年的msg"
  }
});
  • 多行文本—注意了啊:在文本区域插值( <textarea></textarea> ) 并不会生效,应用 v-model 来代替
<div id="app">
<p  style="white-space: pre">
  {{msg}}
</p>
  <br>
  <textarea type="text" v-model="msg"></textarea>
</div>
  • 复选框

    • 单个复选框(直接绑定 true,false)
<div id="app">
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>
new Vue({
  el: "#app",
  data: {
    checked: true
  }
});
  • 多个复选框(将选中的所有 value 绑定到一个数组)
<div id="app">
    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
    <label for="jack">Jack</label>
    <input type="checkbox" id="john" value="John" v-model="checkedNames">
    <label for="john">John</label>
    <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
    <label for="mike">Mike</label>
    <br>
  {{checkedNames}}
</div>
new Vue({
  el: "#app",
  data: {
    checkedNames: []
  }
});
  • 单选按钮(绑定选中的单选框的 value)
<div id="app">
  <input type="radio" id="one" value="One" v-model="picked">
  <label for="one">One</label>
  <br>
  <input type="radio" id="two" value="Two" v-model="picked">
  <label for="two">Two</label>
  <br>
  <span>Picked: {{ picked }}</span>
</div>
new Vue({
  el: "#app",
  data: {
    picked: ""
  }
});
  • 选择列表(不管是单选还是多选,v-model 都要绑定到 select 元素上)

    • 单选列表(绑定到被选中项的 value)
<div id="app">
    <select v-model="selected">
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>
    <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: "#app",
  data: {
    selected: ""
  }
});
  • 多选列表(绑定一个数组,数组的内容是所有的选中项的 value)
<div id="app">
  <select v-model="selected" multiple>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: "#app",
  data: {
    selected: []
  }
});
  • 动态选项
<div id="app">
<select v-model="selected">
  <option v-for="option in options" v-bind:value="option.value">
    {{ option.text }}
  </option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: "#app",
  data: {
    selected: "A",
    options: [
      { text: "One", value: "A" },
      { text: "Two", value: "B" },
      { text: "Three", value: "C" }
    ]
  }
});

v-model修饰符

  • .lazy

    • 由原有的 input 事件变更为 change 事件
<div id="app">
  <input type="text" v-model.lazy="msg">
  {{msg}}
</div>
new Vue({
  el: "#app",
  data: {
    msg: "万年的msg"
  }
});
  • .number
    • 将输入的类型转换成数字类型(NaN 则还是原有类型)
  • .trim
    • 去除两端空白

v-model 与组件

组件

使用组件

  • 注册

    • 注意事项

      • 在初始化根实例前一定要确保注册了组件
      • 名称最好 小写(可以使用短杆)
<div id="app">
  <my-comp></my-comp>
</div>
Vue.component("my-comp", {
  template: "<h3>我是新出炉的组件</h3>"
});
new Vue({
  el: "#app",
  data: {}
});
  • 局部注册
<div id="app">
  <my-comp></my-comp>
</div>
new Vue({
  el: "#app",
  components: {
    "my-comp": { template: "<h3>我是新出炉的组件</h3>" }
  },
  data: {}
});
  • DOM 模板解析说明

    • 自定义组件在这些元素内受限

      • ul

      • ol

      • table

      • select

      • 概要: 解决方案是 使用 特殊的 is 属性

<div id="app">
  <table>
    <tr>
    <my-comp></my-comp>//注意:这样写是绝对错误的,因为tr中只允许有td,这样写他是不认识滴
    </tr>
  </table>
</div>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 上边是错误的

———————————下边是正确的———————————–

<div id="app">
  <table>
    <tr>
      <td is="my-comp"></td>
    </tr>
  </table>
</div>
new Vue({
  el: "#app",
  components: {
    "my-comp": {
      template: "<td>我是组件td</td>"
    }
  },
  data: {}
});
  • 不受限的情况–使用字符串模板
    • <script type="text/x-template"> 怎么用呢?给大家来个例子吧!
<div id="app">
<table>
  <tr>
  <template>
      <my-comp></my-comp>
  </template>
  </tr>
</table>
</div>

<script type="text/x-template" id="myComponent">
          <td>This is a component!</td>
</script>
new Vue({
  el: "#app",
  components: {
    "my-comp": {
      template: "#myComponent"
    }
  },
  data: {}
});
  • JavaScript 内联模板字符串(第二种也给大家解释一下是什么意思,什么是字符串模板)

    <div id="app">
      <table>
        <tr>
        <template>  //这个就是字符串模板
            <my-comp></my-comp>
        </template>
        </tr>
      </table>
    </div>
  • .vue 组件

  • data 必须是函数,在组件中使用 data 中定义的数据,必须使用函数返回,其实这事要说为啥,还得从根上说,我自己的理解,最根本的三个字就是作用域,目的就是为了防止组件中使用的 data 和 vue 实例中的 data 进行相互污染,有机会的话可以给大家讲一下,但是这不是三句两句就能讲清楚的

<div id="app">
  <my-comp></my-comp>
</div>
new Vue({
  el: "#app",
  components: {
    my-comp: {
      template: "<button>{{btncount}}</button>",
      data() {
        return { btncount: 8 };
      }
    }
  },
  data: {
    btncount: 10
  }
});

Prop(子组件从父组件获得数据)

  • 使用 prop 传递数据
  <div id="app">
      <child msg="我是来自于父组件的内容"></child>
  </div>
new Vue({
  el: "#app",
  components: {
    child: {
      props: ["msg"],
      template: "<h2>{{msg}}</h2>"
    }
  }
});

-动态绑定父组件中的数据

<div id="app">
  <input type="text" v-model="fathertext">
      {{fathertext}}
  <child :childText="fathertext"></child>
</div>
new Vue({
  el: "#app",
  components: {
    child: {
      props: ["childtext"],
      template: "<h1>{{childtext}}</h1>"
    }
  },
  data: {
    fathertext: ""
  }
});
  • props 注意事项

    • 一般情况下是数组形式,如果要想规定 props 的数据类型(后面用中括号 [ ])。默认值等(见 props 验证),则是对象了(后面用花括号 { })

    • 关于命名:要不然全小写,要不然 kebabCase(驼峰式),kebab-case(短横线隔开式)Vue 能够正确识别出小驼峰和下划线命名法混用的变量,如这里的forChildMsgfor-child-msg是同一值。

  • 如果出不来,先检查一下命名,看个例子:

<div id="app">
  <input type="text" v-model="msg">
  <child :childMsg="msg"></child>
</div>
new Vue({
  el: "#app",
  components: {
    child: {
      template: "<h1>{{childMsg}}</h1>",
      props: ["childMsg"]
    }
  },
  data: {
    msg: "apple"
  }
});
  • 动态 Prop(使用 v-bind):在模板中,要动态地绑定父组件的数据到子组件模板的 props,和绑定 Html 标签特性一样,使用 v-bind 绑定

    • 局部注册组件
    • 全局注册组件
  • 字面量语法 vs 动态语法

  • 单向数据流

    • 解释

      • 父组件数据更新后,子组件的所有 prop 都会更新为最新值,但是反过来就不会。(注意 :如果 prop 为数组或对象时,子组件改变 prop,父组件的状态也会受到影响,因为数组或对象是引用类型,他们指向同一个内存空间。)如果子组件的 prop 值被修改,则 vue 会给出警告。试一下下边这个例子
<div id="app">
  <parent></parent>
</div>
let childNode = {
  template: `
      <div class="child">
      <div>
        <span>子组件数据</span>
        <input v-model="forChildMsg"/>
      </div>
      <p>{{forChildMsg}}</p>
      </div>`,
  props: {
    "for-child-msg": String
  }
};
let parentNode = {
  template: `
      <div class="parent">
      <div>
        <span>父组件数据</span>
        <input v-model="msg"/>
      </div>
      <p>{{msg}}</p>
      <child :for-child-msg="msg"></child>
      </div>
    `,
  components: {
    child: childNode
  },
  data() {
    return {
      msg: "default string."
    };
  }
};

new Vue({
  el: "#app",
  components: {
    parent: parentNode
  }
});
  • 特殊情况应对方法

    • prop 作为初始值传入后,可能子组件想把它当做局部数据来用的情况

      • 方法:定义一个局部变量,并用 prop 的值初始化它
props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}
//直接使用counter作为子组件的局部变量就可以了
  • prop 作为初始值传入,可能子组件处理成其他数据输出的情况,比如处理成去空格并大写

    • 方法:定义一个计算属性,处理 prop 的值并返回
props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}
  • prop 验证

    • 例子–代码篇
Vue.component("example", {
  props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function() {
        return { message: "hello" };
      }
    },
    // 自定义验证函数
    propF: {
      validator: function(value) {
        return value > 10;
      }
    }
  }
});

自定义事件(子组件将数据传回父组件)

  • 使用 v-on 绑定自定义事件

    • 给组件绑定自定义事件例子(用 v-on 来监听子组件触发的事件)

    • 给组件绑定原生事件例子–使用 native 修饰符

<div id="app">
  <btncomp @click.native="alertE"></btncomp>
</div>
new Vue({
  el: "#app",
  components: {
    btncomp: {
      template: "<button>点击我弹出</button>"
    }
  },
  methods: {
    alertE() {
      alert(777);
    }
  }
});
  • .sync 修饰符(vue 2.3)

    • 目的:使父子组件实现 prop 类似“双向数据绑定”(默认子组件无法更改 prop 的值,上边已经说到了,但是使用 sync 后子组件可以改变 prop 的值,并传回父组件)

    • 使用范例

<div id="app">
  <child :name.sync="name"></child>  //其实不加也能更改,但是会报错
  <button type="button" @click="changePropsInFather">在父组件中将props值改变为'props'</button>
</div>
Vue.component("Child", {
  template: `<h1 @click="changePropsInChild">hello, {{name}}</h1>`,
  props: {
    name: String
  },
  methods: {
    changePropsInChild() {
      this.name = "I am from child";
    }
  }
});
// 实例化一个Vue对象
const app = new Vue({
  el: "#app",
  data() {
    return {
      name: "world"
    };
  },
  methods: {
    changePropsInFather() {
      this.name = "I am from father";
    }
  }
});
  • 使用自定义事件的表单输入组件

    • v-model 的语法糖
<div id="app">
    <input v-model="price">
</div>
new Vue({
  el: "#app",
  data: {
    price: ""
  }
});

我们对 v-model 已经再熟悉不过了,一般都是像上边这样的用法,但是 v-model 只是一个语法糖,它的真身是下边这样:

<div id="app">
<input type="text" :value="price" @input="price = $event.target.value">{{price}}
</div>
new Vue({
  el: "#app",
  data: {
    price: ""
  }
});
  • 例子

    • html 及实例部分和注册组件部分
<div id="app">
  <price-input :value="price" @input="isinputing"></price-input>
  {{price}}
</div>
new Vue({
  el: "#app",
  components: {
    "price-input": {
      template: "<input type='text' @input='update($event.target.value)' />",
      props: ["value"],
      methods: {
        update(val) {
          this.$emit("input", val);
        }
      }
    }
  },
  data: {
    price: ""
  },
  methods: {
    isinputing: function(val) {
      //此处的value就是子组件传递过来的
      this.price = val;
    }
  }
});

非父子组件通信

  • 非父子组件通信(1 父传子是用 props 2 子传父在 vue 中是不允许的,因为 vue 只允许单向数据传递,这时候我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的. 3 那么非父子组件之间通信怎么搞??????)

    • 简单的场景—采用空实例作为中央事件总线,原理就是找一个人来当作一个中转站!
<div id="app1" @click="toApp2">
  我是组件一,点击我给二传值
</div>
<br>
<div id="app2">
  {{app2msg}}
</div>
var bus = new Vue(); // 创建事件中心,创建中转站
new Vue({
  el: "#app1",
  data: {},
  methods: {
    toApp2: function() {
      bus.$emit("change", "上山打老虎"); //使用中转站触发
    }
  }
});

new Vue({
  el: "#app2",
  data: {
    app2msg: ""
  },
  created() {
    bus.$on("change", val => {
      this.app2msg = val; //在组件二创建完成的时候就使用中转站进行监听
    });
  }
});
  • 复杂的场景—专门的状态管理模式 vuex

使用 Slot 分发内容

  • 内容分发概念

    • 为了让组件可以组合(如本子主题的例子),因此需要混合父组件的内容与子组件的自己模板,这一过程就称作内容分发。
<app>
  <app-header></app-header>
  <app-footer></app-footer>
</app>

之前我们的组件,如果给 app 指定了模板,那么里边的 app-header 和 foot 组件的内容就会被覆盖,因此,为了让他们能够组合.需要混用,这就是内容分发

  • 编译作用域

    • 分发内容是在父作用域内编译的
  • 单个 slot(无具名 slot)

    • 为什么用 slot

      • 当父组件中有内容(即自定义的标签名之间有元素–见本子主题的例子) 子组件模板中无 slot 时,则父组件中的内容会被丢弃。
<div id="app">
  <my-comp>
    <p>我是组件中的内容</p>  //这个p会被覆盖
  </my-comp>
</div>
new Vue({
  el: "#app",
  components: {
    "my-comp": {
      template: "<h1>我是一个组件</h1>"
    }
  }
});
  • 那么单个 slot 怎么用呢?
<div id="app">
  <children>
  <span>12345</span>
  <!--上面这行不会显示-->
  </children>
</div>
var vm = new Vue({
  el: "#app",
  components: {
    children: {
      //这个无返回值,不会继续派发
      template: "<button><slot></slot>(我是button)</button>"
    }
  }
});
  • 当父组件中有内容时

    • 子组件中的 slot 会被父组件中内容所替换。(slot 标签也会被替换掉)
  • 当父组件中无内容时

    • 子组件中 slot 内容会被显示出来
  • 具名 slot

    • 用法:保子引父(保持子组件模板,引入父组件参数)–严格按照子组件的模板顺序来即:遇到具名 slot 对应的元素就渲染相应的元素,遇到不具名的 slot,则会渲染除了具名 slot 对应的元素以外的所有元素。
<div id="app">
  <children>
    <span slot="first">12345</span>
    <span slot="second">56789</span>
    <!--上面这行不会显示-->
  </children>
</div>
var vm = new Vue({
  el: "#app",
  components: {
    children: {
      //这个无返回值,不会继续派发
      template:
        "<button><slot name='first'></slot>我是button<slot name='second'></slot>所以使用button标签</button>"
    }
  }
});
// 总结: 说白了, 就是多一个name属性.没啥稀奇玩意;
  • 作用域插槽(特殊的插槽)

    • 作用:使用可复用模板替代已渲染元素

    • 用法:同具名 slot 类似,都是严格按照子组件的模板顺序渲染,只不过遇到 slot 元素时会将父组件中的 template 元素里的元素全部渲染

      • 列表组件例子
<div id="app">
  <child :items="items">
      <template slot="item" scope="props">
          <!--必须存在的具有 scope属性的 template元素(作用域插槽的模板),
          props临时的变量名称,接受子组件中传递的props对象-->
          <!--slot = “item”是具名 slot的用法。-->
          <li>
              {{props.tex}}
              <!--引用子组件中绑定的tex属性值。-->
          </li>
      </template>
  </child>
</div>
Vue.component("child", {
  props: ["items"],
  template:
    '<ul><slot name="item" v-for="item in items" v-bind:tex="item.text"></slot></ul>'
});

new Vue({
  el: "#app",
  data: {
    items: [{ text: "老虎" }, { text: "棒子" }, { text: "鸡" }]
  }
});

动态组件

  • 使用 is 属性(注意,is 前使用了 v-bind!!!通过is来决定那个组件被渲染显示 )
<div id="app">
  <component v-bind:is="show"></component>
  <button v-on:click="changeShow">change show</button>
</div>
var app = new Vue({
  el: "#app",
  data: {
    show: "tem1"
  },
  components: {
    tem1: {
      template: "<div>11111111111</div>"
    },
    tem2: {
      template: "<div>22222</div>"
    },
    tem3: {
      template: "<div>333333</div>"
    }
  },
  methods: {
    changeShow: function() {
      if (this.show == "tem1") {
        this.show = "tem2";
      } else if (this.show == "tem2") {
        this.show = "tem3";
      } else {
        this.show = "tem1";
      }
    }
  }
});
  • keep-active

  • 作用:可保留组件状态或避免重新渲染(包裹动态组件时会缓存不活动的组件实例而不是销毁它们)配合 <keep-alive>使用时,可以保留组件状态避免重新渲染(和 v-show 比较的差别是 v-show 是一开始就渲染的所有组件,而 keep-alive 并不是一开始就渲染好所有组件,而已保留渲染过的组件

  • 注意事项:使用环境应该是较大页面频繁切换的情景下

  • 用法

<div id="app">
  <keep-alive>
    <component v-bind:is="show"></component>
  </keep-alive>
  <button v-on:click="changeShow">change show</button>
</div>
var app = new Vue({
  el: "#app",
  data: {
    show: "tem1"
  },
  components: {
    tem1: {
      template: "<div>11111111111</div>"
    },
    tem2: {
      template: "<div>22222</div>"
    },
    tem3: {
      template: "<div>333333</div>"
    }
  },
  methods: {
    changeShow: function() {
      if (this.show == "tem1") {
        this.show = "tem2";
      } else if (this.show == "tem2") {
        this.show = "tem3";
      } else {
        this.show = "tem1";
      }
    }
  }
});

文章作者: 沐雪
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 沐雪 !
评论
 上一篇
TypeScript学习笔记(一) TypeScript学习笔记(一)
TypeScript 最新整理的笔记放到 oneNote 了 讲真除了几个新加的数据类型,学起来就感觉和学 es6 一样。。。。。。 安装与调试//安装 ts 和 ts-node npm install -D ts-node npm in
2018-09-30
下一篇 
小程序入门 小程序入门
小程序开发 未完成文档 基本结构全局: app.json app.wxss app.js pagepage: wxml wxss js json 移动设备的分辨率和 rpx常见的设计图都是 750px;而不是 375(ip6)呢 pt(
2018-09-06
  目录