vue-8-组件

注册

注册一个全局组件:Vue.component(tagName, options)

Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})
<div id="example">
  <my-component></my-component>
</div>

new Vue({
  el: '#example'
})


局部注册:通过组件实例选项注册
var Child = {
  template: '<div>A custom component!</div>'
}
new Vue({
  el: '#example'components: {//<my-component> 将只在父模板可用
    'my-component': Child
  }
})

使用is属性:

<table>
  <tr is="my-row"></tr>
//==<my-row>...</my-row>,table下标签有HTML的限制可以换用is的形式
</table>

  使用模板,这些限制将不适用:

  1. <script type="text/x-template">

  2. JavaScript 内联模板字符串

  3. .vue 组件

data必须是一个函数,并且,如果返回一个公共的变量,实例之间将共享数据。

props://prop 是单向绑定的

<child my-message="hello!"></child>
//当使用的不是字符串模板,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:
Vue.component('child', { props: ['myMessage'], template: '<span>{{ myMessage }}</span>' })
动态prop:
<div>
  <input v-model="parentMsg">
  <child :my-message="parentMsg"></child>
</div>
 props 传递所有的属性,绑定一个对象:

todo: {
  text: 'Learn Vue',
  isComplete: false
}
<child v-bind="todo"></child>
<!-- 传递实际的 number -->
<comp v-bind:some-prop="1"></comp>
props验证

原生构造器类型:
StringNumberBooleanFunctionObjectArraySymbol
type 也可以是一个自定义构造器函数,使用 instanceof 检测。

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
      }
    }
  }
})

非prop属性,也允许加入到属性,(如一些第三方组件,可以把属性直接添加到组件上 ,不需要事先定义 prop)

<bs-date-input data-3d-date-picker="true"></bs-date-input>

从父组件传来的属性值,如class会和组件模板定义的同名属性合并

自定义事件

<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter> //$on用来监听increment事件
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
//子组件:
Vue.component('button-counter', {
  template: '<button v-on:click="incrementCounter">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementCounter: function () {
      this.counter += 1
      this.$emit('increment') //$emit用来触发increment事件,调用incrementTotal方法
    }
  },
})
new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } })

 .native 修饰符

//在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on
<my-component v-on:click.native="doTheThing"></my-component>

.sync 修饰符

//双向绑定,只是作为一个编译时的语法糖
<comp :foo.sync="bar"></comp>

自定义的表单输入组件

货币筛选器
html:
<div id="app">
  <currency-input label="Price" v-model="price"></currency-input>
  <currency-input label="Shipping" v-model="shipping"></currency-input>
  <currency-input label="Handling" v-model="handling"></currency-input>
  <currency-input label="Discount" v-model="discount"></currency-input>
  <p>Total: ${{ total }}</p>
</div>

js:
Vue.component('currency-input', {
  template: '
    <div>
      <label v-if="label">{{ label }}</label>
      $
      <input
        ref="input"
        v-bind:value="value"
        v-on:input="updateValue($event.target.value)"
        v-on:focus="selectAll"
        v-on:blur="formatValue"
      >
    </div>
  ',
  props: {
    value: {
      type: Number,
      default: 0
    },
    label: {
      type: String,
      default: ''
    }
  },
  mounted: function () {
    this.formatValue()
  },
  methods: {
    updateValue: function (value) {
      var result = currencyValidator.parse(value, this.value)
      if (result.warning) {
        this.$refs.input.value = result.value
      }
      this.$emit('input', result.value)
    },
    formatValue: function () {
      this.$refs.input.value = currencyValidator.format(this.value)
    },
    selectAll: function (event) {
      setTimeout(function () {
          event.target.select()
      }, 0)
    }
  }
})

new Vue({
  el: '#app',
  data: {
    price: 0,
    shipping: 0,
    handling: 0,
    discount: 0
  },
  computed: {
    total: function () {
      return ((
        this.price * 100 + 
        this.shipping * 100 + 
        this.handling * 100 - 
        this.discount * 100
      ) / 100).toFixed(2)
    }
  }
})

自定义组件的v-model,默认一个组件的 v-model 会使用 value 属性和 input 事件,但是诸如单选框、复选框之类的输入类型把 value 属性用作了别的目的。这时需要设置组件的model选项来指定prop和event

<my-checkbox v-model="foo" value="some value"></my-checkbox>
Vue.component('my-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean,
    // this allows using the `value` prop for a different purpose
    value: String
  },
  // ...
})

编译的作用域:

<child-component v-show="someChildProperty"></child-component>
//someChildProperty存在于父作用域

Vue.component('child-component', {
  // someChildProperty存在于子作用域
  template: '<div v-show="someChildProperty">Child</div>',
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

内容分发:插槽

<div>
  <h2>我是子组件的标题</h2>
  <slot>
    只有在没有要分发的内容时才会显示。
  </slot>
 <slot name="footer"></slot>
//具名插槽 </div>
<div>
  <h1>我是父组件的标题</h1>
  <my-component>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
<p slot="footer">这里有一些联系信息</p>
</my-component>
</div>
作用域插槽://子组件的内容可以在父组件指定
父:
<my-awesome-list :items="items">
  <!-- 作用域插槽也可以是具名的 -->
  <template slot="item" scope="props">
    <li class="my-fancy-item">{{ props.text }}</li>
  </template>
</my-awesome-list>

子:
<ul>
  <slot name="item"
    v-for="item in items"
    :text="item.text">
    <!-- 这里写入备用内容 -->
  </slot>
</ul>

动态组件 

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})

<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变化时改变! is指向的组件名随之变化-->
</component>

如果把切换出去的组件保留在内存中, keep-alive,可以保留它的状态或避免重新渲染

<keep-alive>
  <component :is="currentView">
    <!-- 非活动组件将被缓存! -->
  </component>
</keep-alive>

子组件索引:ref 为子组件指定一个索引 ID

<div id="parent">
  <user-profile ref="profile"></user-profile>
</div>

var parent = new Vue({ el: '#parent' })

// 直接访问子组件
var child = parent.$refs.profile

异步组件

全局异步组件:
Vue.component(
  'async-webpack-example',
  () => import('./my-async-component')
)

局部异步组件:
new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

高级异步组件://当一个异步组件被作为 vue-router 的路由组件使用时,这些高级选项都是无效的,因为在路由切换前就会提前加载所需要的异步组件
const AsyncComp = () => ({
  // 需要加载的组件。应当是一个 Promise
  component: import('./MyComp.vue'),
  // loading 时应当渲染的组件
  loading: LoadingComp,
  // 出错时渲染的组件
  error: ErrorComp,
  // 渲染 loading 组件前的等待时间。默认:200ms。
  delay: 200,
  // 最长等待时间。超出此时间则渲染 error 组件。默认:Infinity
  timeout: 3000
})

组件命名约定:

当注册组件 (或者 props) 时,可以使用 kebab-case,camelCase,或 PascalCase。

// 在组件定义中
components: {
  // 使用 kebab-case 形式注册
  'kebab-cased-component': { /* ... */ },
  // register using camelCase
  'camelCasedComponent': { /* ... */ },
  // register using PascalCase
  'PascalCasedComponent': { /* ... */ }
}

在 HTML 模板中,请使用 kebab-case 形式:

<!-- 在 HTML 模板中始终使用 kebab-case -->
<kebab-cased-component></kebab-cased-component>
<camel-cased-component></camel-cased-component>
<pascal-cased-component></pascal-cased-component>

如果组件未经 slot 元素传递内容,你甚至可以在组件名后使用 / 使其自闭合<my-component/>

递归组件:

组件在它的模板内可以递归地调用自己,不过,只有当它有 name 选项时才可以

Vue.component('stack-overflow', {
    template: '<div><stack-overflow></stack-overflow></div>'
})
父组件tree-folder<p>
  <span>{{ folder.name }}</span>
  <tree-folder-contents :children="folder.children"/>
</p>

子组件tree-folder-contents:
<ul>
  <li v-for="child in children">
    <tree-folder v-if="child.children" :folder="child"/>
    <span v-else>{{ child.name }}</span>
  </li>
</ul>
循环引用时,需向注明模块化管理系统循环引用的组件间的处理优先级:

beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}

内联模板

如果子组件有 inline-template 特性,组件将把它的内容当作它的模板,而不是把它当作分发内容。这让模板更灵活,不推荐。

<my-component inline-template>
  <div>
    <p>These are compiled as the component's own template.</p>
    <p>Not parent's transclusion content.</p>
  </div>
</my-component>

模板x-template:

//x-template:
<script type="text/x-template" id="hello-world-template">
  <p>Hello hello hello</p>
</script>
Vue.component('hello-world', {
  template: '#hello-world-template'
})

v-once,缓存模板

Vue.component('terms-of-service', {
  template: '
    <div v-once>
      <h1>Terms of Service</h1>
      ... a lot of static content ...
    </div>
  '
})

 

原文地址:https://www.cnblogs.com/avidya/p/7612434.html