这篇是用 markdown 写的,建议下载一个markdown阅读器 typora,方便阅读。
公司前端项目基本都用的Vue全家桶:
- 路由管理:Vue-Router,官方文档写的很清晰。
 - 数据请求:双控用的Axios、另外有一些项目用的 Vue-Resource。
 - 状态管理:Vuex,目前只有双控项目用到了,官方文档教程写的很清晰,需要花费时间去学习。
 - UI框架使用的Element-UI,注意老项目Element版本不同配置方法。
 - 依赖包管理:基本用的是yarn, 最好别和npm一起混用。
 - css预处理器:sass,sass可以做很多事情,变量、继承、函数、Mixin、运算、循环等、熟练了写起样式会很高效,官方文档教程也讲的很清晰。这是我收藏的几个CSS网站 css-tricks css3-generator gradient box-shadow,能够快速的生成一些好看的CSS效果。
 
可以学一下 ES6 语法,解构赋值、对象的 assign、 展开操作符 、属性名简洁表示、async await 等一些经常会用到。有空的话可以了解下正则(JavaScript 正则表达式迷你书),最近经常能用到。
下面的这些是我在刚开始学习Vue基础部分时做的笔记,整合删改了一些,又添加了一部分示例,基本涵盖了Vue基础知识,供参考,也可以直接看官方文档的教程。我学习Vue时主要也是通过官方文档,把基础部分过一遍,示例代码手敲自己运行一下,刚开始可以先不深究原理,先掌握基础用法,在项目中碰到看不懂的代码再去查阅文档或请教恒哥。
Vue基础知识部分
构造器
- 实例化vue时,需传入一个选项对象,它可以包括 数据、模板、挂载元素、方法和生命周期钩子
 
属性与方法
- 每个vue实例都会代理其data对象里所有的属性
 - vue实例暴露了一些有用的实例属性与方法,这些属性与方法都有前缀$,以便与代理的data属性区分
 
实例生命周期
- created钩子——在实例被创建后被调用
 - mounted—-当编译好的HTML被挂载到对应的位置,这个操作完成后触发
 - updated—-当data中的数据改变,并且虚拟DOM重新渲染完成后触发
 - destroyed
 - 概要: 钩子的this 指向调用它的实例
 
生命周期图示
插值
- 文本
- 双大括号
 - v-text
 
 - 纯HTML
- v-html
 
 - 属性
- v-bind(大双括号不能在属性中使用,因此需使用v-bind)
 
 - 使用JavaScript表达式
 
指令
哪些指令?
- v-bind
 - v-on
 - v-if
 - v-for(特殊)
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26v-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';
}
}
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18v-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
}
}
})修饰符
过滤器
过滤器的目的是用于文本转换,转化成你想要的格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26filters
<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)
}
}
}
})
缩写
计算属性
计算属性(减少模板的复杂度)
- 计算属性的基础写法
 
1  | computed  | 
计算缓存vs方法(Methods)
- 计算属性computed具有缓存,而methods无缓存
 
Computed属性vs 侦听器(Watch属性)
- watch方法–观察Vue实例上的数据变动,只要指定的数据改变就会执行预定的函数
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25watch
<div id="app">
{{msg}} <br>
改变了吗? {{isChange}}
<button @click="change">改变</button>
</div>
new Vue({
el: "#app",
data: {
msg:'111',
isChange:'No'
},
watch:{
//只要msg改变,这个方法就会执行
msg(val,oldVal){
this.isChange = 'Yes'
}
},
methods:{
change(){
this.msg = '222'
}
}
})- computed方法
 
计算setter 和getter
- get和set,顾名思义,一个是获得,一个是设置,常规上来讲,计算属性中都是有get和set方法的,默认是只有getter方法,如果需要的话,自然可以写一个setter方法.
 
1  | get和set  | 
class与style绑定
绑定HTML class
对象语法
- 基本
 - 在对象中传入多个class属性(其会与原有class共存)
 - 直接传入对象
 - 与计算属性一起使用(绑定返回对象的计算属性)
 
数组语法
- 简单例子
 - 三元表达式
 - 当有多个条件class时,可以在数组语法中使用对象语法
 
用在组件上
- 简单例子
 - 绑定HTML class例子
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19绑定class的几种方式
.classC{
color:red;
}
.classD{
font-weight:bold;
}
.classE{
font-size:20px;
}
.classF{
color:blue;
}
.classM{
display:block;
}
.classN{
display:none;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<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>
1  | new Vue({  | 
绑定内联样式
- 对象语法
- 内联式对象语法
 - 样式对象式对象语法(更推荐)
 
 - 数组语法
 - 自动添加前缀
- v-bind:style 当需要特定的前缀时如transform,vue.js会自动添加
 
 - 多重值
- 可以为一个属性添加多个值的数组,常用于含有多个前缀的情况
 
 
条件渲染
v-if(v-else)是真正的渲染
template元素与v-if
v-else(需要紧跟在v-if后边)
v-else-if
用key管理可复用的元素
- 例子:用户名和邮箱登录界面 如果有key就不会复用,可以把key去试一下,然后输入看一下效果
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<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
包含所有类型的例子 
1  | <template>  | 
key
作用
- 用v-for更新已渲染过的列表时,它默认采用的是“就地复用”的原则,也就是如果数据项顺序发生了改变,vue将不是移动DOM元素来匹配数据项的顺序,而是简单复用此处的元素。如果想跟踪每个节点的身份,从而重用或重新排列现有元素,可使用key。
 
key有什么用,
1
2
3
4
5
6
7
8
9
10<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>
1  | new Vue({  | 
因为加上key默认采取的就是就地复用策略
    1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
### 数组更新检测
- 变异方法(会改变原有数组)
  - 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)
1
2
—
var vmm = 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:’关羽’})
    }
  }
})
1  | 
- 修改数组长度时,vue不能检测变动,如:vm.items.length = newLength
 - 只能用example1.items.splice(newLength)
 
1  | 
  | 
计算属性应用于过滤
    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;
        })
      }
   }
  })
1  | 
//在v-for循环中直接嵌入方法
  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;
          })
      }
      }
  })
1  | 
  | 
1
2
new Vue({
el: “#app”,
methods: {
sayHello: function(){
alert(‘sayHello’)
}
}
})
1  | 
  | 
  new Vue({
    el: “#app”,
    data: {
        msg:’’
    },
    methods: {
        showBtnname: function(e){
          this.msg = e.target.innerText;
      }
    }
  })
1  | 
  | 
  —————————-html———————————
  
Todos:
      <del v-if="todo.done">
        {{ todo.text }}
      </del>
      <span v-else>
        {{ todo.text }}
      </span>
    </label>
  </li>
</ol>
  
  —————————-js———————————
  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
      }
    }
  })
  —————————-css———————————
  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);
  }
1  | 
  | 
  new Vue({
    el: “#app”,
    data: {
        num:0
    }
  })
1  | 
  | 
  new Vue({
    el: “#app”,
    data: {
     msg:’万年的msg’
    }
  })
1  | 
  | 
    
  
1  | 
  | 
<div id="app">
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>
new Vue({
  el: "#app",
  data: {
   checked:true
  }
})
1
2
- 多个复选框(将选中的所有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:[]
  }
})
1
2
- 单选按钮(绑定选中的单选框的value)
  Picked:
  new Vue({
    el: “#app”,
    data: {
      picked:’’
    }
  })
1  | 
  | 
<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:''
  }
})
1
2
- 多选列表(绑定一个数组,数组的内容是所有的选中项的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: []
  }
})
1
2
- 动态选项
<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' }
    ]
  }
})
1
2
3
4
5
6
### 修饰符
- .lazy
  - 由原有的input事件变更为change事件
<div id="app">
  <input type="text" v-model.lazy="msg">
  {{msg}}
</div>
new Vue({
  el: "#app",
  data: {
    msg:'万年的msg'
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- .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: {
  }
})
1
2
- 局部注册
    new Vue({
    el: “#app”,
    components:{
        ‘my-comp’:{template:’
我是新出炉的组件
‘}},
data: {
}
})
1  | 
  | 
  <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: {
    }
  })
  1
2
3
4
- 不受限的情况--使用字符串模板
  - <script type="text/x-template">  怎么用呢?给大家来个例子吧!
  -------------------------------HTML-----------------------------------------
  <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>
  -----------------------------------JS----------------------------------
  new Vue({
    el: "#app",
    components:{
        'my-comp':{
              template:'#myComponent'
      }
    },
    data: {
    }
  })
  1
2
- JavaScript内联模板字符串(什么是字符串模板)
  <div id="app">
   <table>
     <tr>
     <template>  //这个就是字符串模板
         <my-comp></my-comp>
     </template>
     </tr>
   </table>
  </div>
  1
2
3
4
  - .vue组件  (第三种)
- data必须是函数,在组件中使用data中定义的数据,必须使用函数返回,我自己的理解,最根本的三个字就是作用域,目的就是为了防止组件中使用的data和vue实例中的data进行相互污染,
<div id="app">
<mycomp></mycomp>
</div>
new Vue({
  el: "#app",
  components:{
      'mycomp':{
            template:'<button>{{btncount}}</button>',
       data(){
          return {btncount:8}
        }
    }
  },
  data:{
      btncount:10
  }
})
1
2
3
4
### Prop(子组件从父组件获得数据)
- 使用prop传递数据
<div id="app">
    <child msg="我是来自于父组件的内容"></child>
</div>
new Vue({
  el: "#app",
  components:{
      'child':{
        props:['msg'],
        template:'<h2>{{msg}}</h2>'
    }
  }
})
1
2
          动态绑定父组件中的数据
  <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:''
    }
  })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  - 
  - props注意事项
    - 一般情况下是数组形式,如果要想规定props的数据类型(后面用中括号 [ ])。默认值等(props验证),则是对象了(后面用花括号  {  })
- 关于命名:要不然全小写,要不然kebabCase(驼峰式),kebab-case(短横线隔开式)Vue 能够正确识别出小驼峰和下划线命名法混用的变量,如这里的`forChildMsg`和`for-child-msg`是同一值。 
- 动态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
    }
  })
  1
2
3
4
5
6
- 特殊情况应对方法
  - prop作为初始值传入后,可能子组件想把它当做局部数据来用的情况
    - 方法:定义一个局部变量,并用prop的值初始化它
    props: ['initialCounter'],
    data: function () {
      return { counter: this.initialCounter }
    }
    //直接使用counter作为子组件的局部变量就可以了
    1
2
3
4
- prop作为初始值传入,可能子组件处理成其他数据输出的情况,比如处理成去空格并大写
  - 方法:定义一个计算属性,处理prop的值并返回
    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }
    1
2
3
4
- 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
      }
    }
  }
})
1
2
3
4
5
6
7
8
### 自定义事件(子组件将数据传回父组件)
- 使用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)
    }
  }
})
1
2
3
4
5
6
- .sync修饰符
  - 目的:使父子组件实现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'
        },
      },
    })
1
2
3
4
5
6
- 使用自定义事件的表单输入组件
  - 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: ''
     }
 });
1
2
3
4
- 例子
  - 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
2
3
4
5
6
### 非父子组件通信
- 非父子组件通信(1 父传子是用props  2 子传父在vue中是不允许的,因为vue只允许单向数据传递,这时候我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的. 
  - 简单的场景---采用空实例作为中央事件总线(EventBus),原理就是找一个人来当作一个中转站!
 <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; //在组件二创建完成的时候就使用中转站进行监听
    })
  }
})
1
2
3
4
5
6
7
8
  - 复杂的场景---专门的状态管理模式vuex
### 使用Slot分发内容
- 内容分发概念
  - 为了让组件可以组合,因此需要混合父组件的内容与子组件的自己模板,这一过程就称作内容分发。
<app>
  <app-header></app-header>
  <app-footer></app-footer>
</app>
如果给app指定了模板,那么里边的app-header和foot组件的内容就会被覆盖,因此,为了让他们能够组合.需要混用,这就是内容分发
1
2
3
4
5
6
7
8
9
10
- 编译作用域
  - 分发内容是在父作用域内编译的
- 单个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>'
      }
    }
  })
  1
2
单个slot怎么用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<div id="app">
<children>
<span>12345</span>
<!--上面这行不会显示-->
</children>
</div>
var vm = new Vue({
el: '#app',
components: {
children: { //这个无返回值,不会继续派发
template: "<button><slot></slot>(我是button)</button>"
}
}
});
1  | 
  | 
<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属性
1
2
3
4
5
6
7
8
- 作用域插槽(特殊的插槽)
  - 作用:使用可复用模板替代已渲染元素
  - 用法:同具名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:'h'},
              {text:'y'},
              {text:'z'}
          ]
      }
  })
  1
2
3
4
### 动态组件
- 使用is属性(注意,is前使用了v-bind!!!通过**is**来决定那个组件被渲染显示 )
   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'
              }
          }
      }
  })
  1  | 
  | 
        <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'
                    }
                }
            }
        })
```