vue从入门到进阶:组件Component详解(六)

前端开发 作者: 2024-08-20 20:30:01
一.什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功

全局注册

<div id="example">
  my-component></>
</div>
// 注册
Vue.component('my-component',{
  template: '<div>A custom component!</div>'
})
var vm = new Vue({
  el: '#example'
>A custom component!>
 注册
var MyComponent = Vue.extend({
  template: '<div>A custom component!</div>'
});

Vue.extend()使用说明

="mount-point">
 创建构造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>'function () {
    return {
      firstName: 'Walter''Heisenberg'
    }
  }
})
 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
p>Walter White aka Heisenberg>

vm.$mount( [elementOrSelector] )使用说明

  • {Element | string} [elementOrSelector]
  • {boolean} [hydrating]
 Vue.extend({
  template: '<div>Hello!</div>'
})

 创建并挂载到 #app (会替换 #app)
new MyComponent().$mount('#app')

 同上
new MyComponent({ el: '#app' })

 或者,在文档之外渲染并且随后挂载
var component =  MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)

局部注册

var Child = {
  template: '<div>A custom component!</div>'
}

 Vue({
   ...
  components: {
     <my-component> 将只在父组件模板中可用
    'my-component': Child
  }
})

DOM 模板解析注意事项

tablemy-row>...>
tr is="my-row"tr>
  • <script type="text/x-template">
  • JavaScript 内联模板字符串
  • .vue 组件

data 必须是函数

Vue.component('my-component''hello'
  }
})
="example-2"simple-countervar data = { counter: 0 }

Vue.component('simple-counter' 技术上 data 的确是一个函数了,因此 Vue 不会警告,
   但是我们却给每个组件实例返回了同一个对象的引用
  data:  data
  }
})

 Vue({
  el: '#example-2'
})
data:  () {
   {
    counter: 0
  }
}

使用 Prop 传递数据

Vue.component('child' 声明 props
  props: ['message'],1)"> 就像 data 一样,prop 也可以在模板中使用
   同样也可以在 vm 实例中通过 this.message 来使用
  template: '<span>{{ message }}</span>'
})

<child message="hello!"></child>
Vue.component('child' 在 JavaScript 中使用 camelCase
  props: ['myMessage'
})

<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>

动态 Prop

input v-model="parentMsg"brchild v-bind:my-messagechild>
:my-message>
todo: {
  text: 'Learn Vue'false
}
todo-item v-bind="todo"todo-item>
todo-item
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"
>

字面量语法 vs 动态语法

<!-- 传递了一个字符串 "1" -->
comp some-prop="1"comp>
 传递真正的数值 v-bind:some-prop>

单向数据流

  • Prop 作为初始值传入后,子组件想把它当作局部数据来用;
  • Prop 作为原始数据传入,由子组件处理成其它数据输出。
props: ['initialCounter'return { counter: this.initialCounter }
}
props: ['size'return .size.trim().toLowerCase()
  }
}

Prop 验证

Vue.component('example' 基础类型检测 (`null` 指允许任何类型)
    propA: Number,1)"> 可能是多种类型
    propB: [String,Number],1)"> 必传且是字符串
    propC: {
      type: String,required: true
    },1)"> 数值且有默认值
    propD: {
      type: Number,1)">default: 100 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,1)">default:  () {
        return { message: 'hello' }
      }
    },1)"> 自定义验证函数
    propF: {
      validator:  (value) {
        return value > 10
      }
    }
  }
})
Vue.component('modal'    
    }
  }
});
bs-date-input data-3d-date-picker="true"bs-date-input>
type="date" class="form-control">
bs-date-input
  ="true"
  class="date-picker-theme-dark"
>

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

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件
="counter-event-example">{{ total }}button-counter v-on:increment="incrementTotal"button-counter>
Vue.component('button-counter' {
      counter: 0
    }
  },methods: {
    incrementCounter:  () {
      this.counter += 1
      this.$emit('increment')
    }
  },})

 Vue({
  el: '#counter-event-example'
  },methods: {
    incrementTotal: this.total += 1
    }
  }
})

给组件绑定原生事件.native

my-component v-on:click.native="doTheThing">

.sync 修饰符(2.3.0+)

:foo.sync="bar">
:foo="bar" @update:foo="val => bar = val">
this.$emit('update:foo',newValue)

使用自定义事件的表单输入组件

="something">
input
  v-bind:value="something"
  v-on:input="something = $event.target.value">
custom-input
  ="something = arguments[0]"custom-input>
  • 接受一个 value prop
  • 在有新的值时触发 input 事件并将新值作为参数
="app">
      custom-input >
    />
    {{something}}
 注册
Vue.component('custom-input''<input type="text"  v-bind:value="something" v-on:input="updateValue($event.target.value)"/>'(value){
           this.$emit('input' Vue({
  el: '#app'
  }
  
})
currency-input ="price"currency-input>
Vue.component('currency-input'\
    <span>\
      $\
      <input\
        ref="input"\
        v-bind:value="value"\
        v-on:input="updateValue($event.target.value)"\
      >\
    </span>\
  ' 不是直接更新值,而是使用此方法来对输入值进行格式化和位数限制
    updateValue:  (value) {
      var formattedValue = value
         删除两侧的空格符
        .trim()
         保留 2 位小数
        .slice(
          0 value.length
            : value.indexOf('.') + 3
        )
       如果值尚不合规,则手动覆盖为合规的值
      if (formattedValue !== value) {
        this.$refs.input.value = formattedValue
      }
       通过 input 事件带出数值
      
currency-input 
    label="Price" 
    v-model="price"
  ="Shipping"="shipping"
  ="Handling"="handling"
  ="Discount"="discount"
  >
  
  >Total: ${{ total }}\
    <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>\
  'default: 0default: ''.formatValue()
  },methods: {
    updateValue: var result = currencyValidator.parse(value,.value)
      if (result.warning) {
         result.value
      }
      this.$refs.input.value = currencyValidator.format(.value)
    },selectAll:  (event) {
       Workaround for Safari bug
       http://stackoverflow.com/questions/1269722/selecting-text-on-focus-using-jquery-not-working-in-safari-and-chrome
      setTimeout( () {
          event.target.select()
      },0)
    }
  }
})

00 ((
        this.price * 100 + 
        this.shipping * 100 + 
        this.handling * 100 - 
        this.discount * 100
      ) / 100).toFixed(2)
    }
  }
})

自定义组件的 v-model(2.2.0 新增)

Vue.component('my-checkbox''change' 这样就允许拿 `value` 这个 prop 做其它事了
    value: String
  },1)"> ...
})
my-checkbox ="foo" value="some value"my-checkbox>
my-checkbox
  :checked
  @change="val => { foo = val }"
  value>
>
    {{foo}}
>
Vue.component('my-checkbox'(){
       {
          ischecked:.checked
      }
  },methods:{
      changefun(state){
          this.ischecked = !state;
          this.$emit('change',1)">.ischecked);
      }
  }
})

  }
  
})

非父子组件的通信

var bus = new Vue()
 触发组件 A 中的事件
bus.$emit('id-selected',1)
 在组件 B 创建的钩子中监听事件
bus.$on('id-selected',1)"> (id) {
   ...
})
>
     comp-a v-on:id-selected="getdate"comp-acomp-b Vue();

Vue.component('comp-a' {
          
      }
  },methods:{
      comfuna(){
          bus.$emit('id-selected',1);
          this.$emit('id-selected',1)">);
      }
  }
})
Vue.component('comp-b' 在组件 B 创建的钩子中监听事件
    bus.$on('id-selected',1)"> (id) {
         console.log('在B组件中得到的值:'+id);
    })
  }
 
})
value);
      }
  }
  
})
appapp-headerapp-footer>
  • <app> 组件不知道它会收到什么内容。这是由使用 <app> 的父组件决定的。
  • <app> 组件很可能有它自己的模板。
 无效 child-component v-show="someChildProperty"child-component>
Vue.component('child-component' 有效,因为是在正确的作用域内
  template: '<div v-show="someChildProperty">Child</div>' {
      someChildProperty: 
    }
  }
})

单个插槽

h2>我是子组件的标题slot
    只有在没有要分发的内容时才会显示。
  >
h1>我是父组件的标题>这是一些初始内容>这是更多的初始内容>
>

具名插槽

class="container"headerslot name="header"mainfooter="footer"app-layouth1 >这里可能是一个页面标题>

  >主要内容的一个段落。>另一个主要段落。p >这里有一些联系信息>
>

作用域插槽(2.1.0 新增)

="child"text="hello from child">
="parent"template slot-scope="props"span>hello from parent>{{ props.text }}template>
>hello from child>
my-awesome-list :items="items" 作用域插槽也可以是具名的 -->
  li
    ="item"
    slot-scope="props"
    class="my-fancy-item"
    {{ props.text }}
  limy-awesome-list>
ul
    v-for="item in items"
    :text="item.text" 这里写入备用内容 >
span ="{ text }">{{ text }}>
/* ... */ },posts: {  }
  }
})
component v-bind:is="currentView" 组件在 vm.currentview 变化时改变! component>
var Home = {
  template: '<p>Welcome home!</p>'keep-alive

keep-alive:is 非活动组件将被缓存! >

编写可复用组件

  • Prop 允许外部环境传递数据给组件;
  • 事件允许从组件内触发外部环境的副作用;
  • 插槽允许外部环境将额外的内容组合在组件中。
my-component
  ="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat"
img ="icon" src="..."="main-text">Hello!>

子组件引用

user-profile ref="profile"user-profilevar parent = new Vue({ el: '#parent' })
 访问子组件实例
var child = parent.$refs.profile

异步组件

Vue.component('async-example',1)"> (resolve,reject) {
  setTimeout( 将组件定义传入 resolve 回调函数
    resolve({
      template: '<div>I am async!</div>'
    })
  },1000)
})
Vue.component('async-webpack-example',1)"> (resolve) {
   这个特殊的 require 语法告诉 webpack
   自动将编译后的代码分割成不同的块,
   这些块将通过 Ajax 请求自动下载。
  require(['./my-async-component'
Vue.component(
  'async-webpack-example' 该 `import` 函数返回一个 `Promise` 对象。
  () => import('./my-async-component')
)
  components: {
    'my-component': () => import('./my-async-component')
  }
})

高级异步组件(2.3.0 新增)

const AsyncComp = () => ({
   需要加载的组件。应当是一个 Promise
  component: import('./MyComp.vue'),1)"> 加载中应当渲染的组件
  loading: LoadingComp,1)"> 出错时渲染的组件
  error: ErrorComp,1)"> 渲染加载中组件前的等待时间。默认:200ms。
  delay: 200 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
  timeout: 3000
})

组件命名约定

 在组件定义中
components: {
   使用 kebab-case 注册
  'kebab-cased-component': {  使用 camelCase 注册
  'camelCasedComponent': {  使用 PascalCase 注册
  'PascalCasedComponent': {  }
}
 在 HTML 模板中始终使用 kebab-case kebab-cased-componentcamel-cased-componentpascal-cased-component>
  • kebab-case
  • camelCase 或 kebab-case (如果组件已经被定义为 camelCase)
  • kebab-case、camelCase 或 PascalCase (如果组件已经被定义为 PascalCase)
components: {
  'kebab-cased-component': {  }
}
>

camelCasedComponentpascalCasedComponentPascalCasedComponent>

递归组件

name: 'unique-name-of-my-component'
Vue.component('unique-name-of-my-component' ...
})
name: 'stack-overflow'组件间的循环引用

>{{ folder.name }}tree-folder-contents :children="folder.children"/>
>
li v-for="child in children"tree-folder v-if="child.children" :folder/>
    v-else>{{ child.name }}>
Failed to mount component: template or render function not defined.
beforeCreate: this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue')
}

X-Template

script ="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'\
    <div v-once>\
      <h1>Terms of Service</h1>\
      ...很多静态内容...\
    </div>\
  '
})
原创声明
本站部分文章基于互联网的整理,我们会把真正“有用/优质”的文章整理提供给各位开发者。本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
本文链接:http://www.jiecseo.com/news/show_65706.html