vue组件

vue组件

全局组件定义的三种方式

1. 使用 Vue.extend 配合 Vue.component 方法:
//第一种
   var login = Vue.extend({
      template: '

登录

'
}); Vue.component('login', login); //第二种 Vue.component('mycom1', Vue.extend({ template: '

这是使用 Vue.extend 创建的组件

'
}))
2. 直接使用 Vue.component 方法:
Vue.component('register', {
      template: '

注册

'
});
3. 将模板字符串,定义到script标签种:
<script id="tmpl" type="x-template">
      <div><a href="#">登录</a> | <a href="#">注册</a></div>
    </script>

同时,需要使用 Vue.component 来定义组件:

Vue.component('account', {
      template: '#tmpl'
    });

注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!

局部组件


<div id="app">
    <runoob></runoob>
</div>
 
<script>
var Child = {
  template: '

自定义组件!

'
} // 创建根实例 new Vue({ el: '#app', components: { // 将只在父模板可用 'runoob': Child } }) </script>

组件中展示数据和响应事件

  • 组件可以有自己的 data 数据
  • 组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是 组件中的 data 必须是一个方法
  • 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行;
  • 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!

在组件中,data需要被定义为一个方法,例如:

 <script>
   Vue.component('mycom1', {
     template: '

这是全局组件 --- {{msg}}

'
, data: function () { return { msg: '这是组件的中data定义的数据' } } }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script>

使用components属性定义局部子组件

组件实例定义方式:

<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      components: { // 定义子组件
        account: { // account 组件
          template: '

这是Account组件{{name}}

'
, // 在这里使用定义的子组件 components: { // 定义子组件的子组件 login: { // login 组件 template: "

这是登录组件

"
} } } } }); </script>

引用组件:

<div id="app">
    <account></account>
  </div>

重点】为什么组件中的data属性必须定义为一个方法并返回一个对象

通过计数器案例演示

<div id="app">
    <counter></counter>
    <hr>
    <counter></counter>
    <hr>
    <counter></counter>
  </div>
  <template id="tmpl">
    <div>
      <input type="button" value="+1" @click="increment">
      <h3>{{count}}</h3>
    </div>
  </template>
  <script>
    var dataObj = { count: 0 }

    // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1
    Vue.component('counter', {
      template: '#tmpl',
      data: function () {
        // return dataObj
        return { count: 0 }
      },
      methods: {
        increment() {
          this.count++
        }
      }
    })
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {}
    });
  </script>

vue组件_第1张图片

使用flag标识符结合v-ifv-else切换组件

页面结构:

<div id="app">
    <input type="button" value="toggle" @click="flag=!flag">
    <my-com1 v-if="flag"></my-com1>
    <my-com2 v-else="flag"></my-com2>
  </div>

Vue实例定义:

<script>
    Vue.component('myCom1', {
      template: '

奔波霸

'
}) Vue.component('myCom2', { template: '

霸波奔

'
}) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { flag: true }, methods: {} }); </script>

使用:is属性来切换不同的子组件,并添加切换动画

组件实例定义方式:
  // 登录组件
    const login = Vue.extend({
      template: `<div>
        <h3>登录组件</h3>
      </div>`
    });
    Vue.component('login', login);

    // 注册组件
    const register = Vue.extend({
      template: `<div>
        <h3>注册组件</h3>
      </div>`
    });
    Vue.component('register', register);

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: { comName: 'login' },
      methods: {}
    });
使用component标签,来引用组件,并通过:is属性来指定要加载的组件:

页面结构:

 <div id="app">
    <a href="" @click.prevent="comName='login'">登录</a>
    <a href="" @click.prevent="comName='register'">注册</a>
    // Vue提供了 component ,来展示对应名称的组件
    //component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称
    <component :is="comName"></component>
  </div>

Vue实例定义:

<script>
    // 组件名称是 字符串
    Vue.component('login', {
      template: '

登录组件

'
}) Vue.component('register', { template: '

注册组件

'
}) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); </script>
添加切换样式:

css样式:

  <style>
    .v-enter,
    .v-leave-to {
      opacity: 0;
      transform: translateX(30px);
    }

    .v-enter-active,
    .v-leave-active {
      position: absolute;
      transition: all 0.3s ease;
    }

    h3{
      margin: 0;
    }
  </style>

父组件向子组件传值

Prop

prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 “prop”:

<div id="app">
    <child message="hello!"></child>
</div>
<script>
// 注册
Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 同样也可以在 vm 实例中像 "this.message" 这样使用
  template: '{{ message }}'
})
// 创建根实例
new Vue({
  el: '#app'
})
</script>

动态 Prop

类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:

<div id="app">
    <div>
      <input v-model="parentMsg">
      <br>
      <child v-bind:message="parentMsg"></child>
    </div>
</div>
<script>
// 注册
Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 同样也可以在 vm 实例中像 "this.message" 这样使用
  template: '{{ message }}'
})
// 创建根实例
new Vue({
  el: '#app',
  data: {
    parentMsg: '父组件内容'
  }
})
</script>

以下实例中使用 v-bind 指令将 todo 传到每一个重复的组件中:


<div id="app">
    <ol>
    <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
      </ol>
</div>
 
<script>
Vue.component('todo-item', {
  props: ['todo'],
  template: '
  • {{ todo.text }}
  • '
    }) new Vue({ el: '#app', data: { sites: [ { text: 'Runoob' }, { text: 'Google' }, { text: 'Taobao' } ] } }) </script>

    注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。

    Prop 验证

    组件可以为 props 指定验证要求。

    为了定制 prop 的验证方式,可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

    Vue.component('my-component', {
      props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        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 ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })
    

    当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

    type 可以是下面原生构造器:

    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol

    type 也可以是一个自定义构造器,使用 instanceof 检测。

    子组件向父组件传值

    1. 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
    2. 父组件将方法的引用传递给子组件,其中,getMsg是父组件中methods中定义的方法名称,func是子组件调用传递过来方法时候的方法名称
    <son @func="getMsg"></son>
    
    1. 子组件内部通过this.$emit('方法名', 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
    <div id="app">
        <!-- 引用父组件 -->
        <son @func="getMsg"></son>
        <!-- 组件模板定义 -->
        <script type="x-template" id="son">
          <div>
            <input type="button" value="向父组件传值" @click="sendMsg" />
          </div>
        </script>
      </div>
    
      <script>
        // 子组件的定义方式
        Vue.component('son', {
          template: '#son', // 组件模板Id
          methods: {
            sendMsg() { // 按钮的点击事件
              this.$emit('func', 'OK'); // 调用父组件传递过来的方法,同时把数据传递出去
            }
          }
        });
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {
            getMsg(val){ // 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义
              alert(val);
            }
          }
        });
      </script>
    

    评论列表案例

    <div id="app">
        <cmt-box @func="loadComments"></cmt-box>
        <ul class="list-group">
          <li class="list-group-item" v-for="item in list" :key="item.id">
            <span class="badge">评论人: {{ item.user }}</span>
            {{ item.content }}
          </li>
        </ul>
      </div>
      <template id="tmpl">
        <div>
          <div class="form-group">
            <label>评论人:</label>
            <input type="text" class="form-control" v-model="user">
          </div>
          <div class="form-group">
            <label>评论内容:</label>
            <textarea class="form-control" v-model="content"></textarea>
          </div>
          <div class="form-group">
            <input type="button" value="发表评论" class="btn btn-primary" @click="postComment">
          </div>
        </div>
      </template>
      <script>
        var commentBox = {
          data() {
            return {
              user: '',
              content: ''
            }
          },
          template: '#tmpl',
          methods: {
            postComment() { // 发表评论的方法
              // 分析:发表评论的业务逻辑
              // 1. 评论数据存到哪里去???   存放到了 localStorage 中  localStorage.setItem('cmts', '')
              // 2. 先组织出一个最新的评论数据对象
              // 3. 想办法,把 第二步中,得到的评论对象,保存到 localStorage 中:
              //  3.1 localStorage 只支持存放字符串数据, 要先调用 JSON.stringify 
              //  3.2 在保存 最新的 评论数据之前,要先从 localStorage 获取到之前的评论数据(string), 转换为 一个  数组对象, 然后,把最新的评论, push 到这个数组
              //  3.3 如果获取到的 localStorage 中的 评论字符串,为空不存在, 则  可以 返回一个 '[]'  让 JSON.parse 去转换
              //  3.4  把 最新的  评论列表数组,再次调用 JSON.stringify 转为  数组字符串,然后调用 localStorage.setItem()
    
              var comment = { id: Date.now(), user: this.user, content: this.content }
    
              // 从 localStorage 中获取所有的评论
              var list = JSON.parse(localStorage.getItem('cmts') || '[]')
              list.unshift(comment)
              // 重新保存最新的 评论数据
              localStorage.setItem('cmts', JSON.stringify(list))
    
              this.user = this.content = ''
    
              // this.loadComments() // ?????
              this.$emit('func')
            }
          }
        }
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            list: [
              { id: Date.now(), user: '李白', content: '天生我材必有用' },
              { id: Date.now(), user: '江小白', content: '劝君更尽一杯酒' },
              { id: Date.now(), user: '小马', content: '我姓马, 风吹草低见牛羊的马' }
            ]
          },
          beforeCreate(){ // 注意:这里不能调用 loadComments 方法,因为在执行这个钩子函数的时候,data 和 methods 都还没有被初始化好
    
          },
          created(){
            this.loadComments()
          },
          methods: {
            loadComments() { // 从本地的 localStorage 中,加载评论列表
              var list = JSON.parse(localStorage.getItem('cmts') || '[]')
              this.list = list
            }
          },
          components: {
            'cmt-box': commentBox
          }
        });
      </script>
    

    vue组件_第2张图片

    你可能感兴趣的:(vue,vue,组件)