组件(一)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>组件</title>
<script type="text/javascript" src="js/vue.js" ></script>
<script src="https://cdn.rawgit.com/chrisvfritz/5f0a639590d6e648933416f90ba7ae4e/raw/974aa47f8f9c5361c5233bd56be37db8ed765a09/currency-validator.js"></script>
</head>
<body>
<!--简单的组件实例 -->
<!--test1.1:注册全局组件-->
<div id="app">
app-1:<my-component></my-component>
</div>
<script>
//注册全局组件 使用 Vue.component(tagName, options)
Vue.component('my-component', {
template:"<input type='radio' />"
})
var vm =new Vue({
el:"#app",
data:''
})
</script>
<!--test:1.2 局部注册-->
<div id="app-2">
<Child></Child>
</div>
<script>
var Child = {
template: '<div>app-2:A custom component!</div>'
}
var vm1 =new Vue({
el:"#app-2",
data:'',
/*局部注册通过实例选项 components 紧在当前作用域可用*/
components:{
'Child':Child
}
})
</script>
<!--test3:在一些仅支持内部标签的html标签 我们可以用is进行引用 以便解决不兼容的问题-->
<div id="app-3">
<table>
<tr is="Child">
</tr>
</table>
</div>
<script>
var Child = {
template: '<tr><td>app-3:one。。</td><td>two。。</td></tr>'
}
var vm2 =new Vue({
el:"#app-3",
data:'',
components:{
'Child':Child
}
})
</script>
<!--test4:组件实例中data 必须是函数-->
<!--test4.1这里我们演示返回同一个对象的引用 达到同步的效果-->
<div id="app-4">
test4:
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
<script>
var data = { counter: 0 }
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// 技术上 data 的确是一个函数了,因此 Vue 不会警告,
// 但是我们却给每个组件实例返回了同一个对象的引用
data: function () {
return data
}
})
new Vue({
el: '#app-4'
})
</script>
<!--test4.2:这里我们演示各自内部状态的效果-->
<div id="app-5">
test5:
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
<script>
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// 技术上 data 的确是一个函数了,因此 Vue 不会警告,
// 但是我们却给每个组件实例返回了同一个对象的引用
data: function () {
return { counter: 0 }
}
})
new Vue({
el: '#app-5'
})
</script>
<!--组件组合 父子组件-->
<!--test6.1:父向子传值 通过给组件生命一个属性 porps 来声明式传值-->
<div id="app-6">
test6.1:
<child :message="message"></child>
</div>
<script>
Vue.component('child', {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 也可以在模板中使用
// 同样也可以在 vm 实例中通过 this.message 来使用
template: '<span>{{ message }}</span>'
})
new Vue({
el: '#app-6',
data:{
message:'这是 test6'
}
})
</script>
<!--test6.2:父向子传值 传对象-->
<div id="app-7">
test6.2:
<todo-item v-bind="todo"></todo-item>
<!--
等价于<todo-item
v-bind:text="todo.text"
v-bind:is-complete="todo.isComplete"
></todo-item>
-->
</div>
<script>
Vue.component('todo-item', {
props: ['text','is-complete'],
template: '<span>{{ text }}。。。。。。{{isComplete}}</span>'
})
new Vue({
el: '#app-7',
data:{
todo: {
text: 'Learn Vue',
isComplete: "123"
}
}
})
</script>
<!--prop的验证-->
<script>
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
}
}
}
})
</script>
<!--test7
子给父传参数 自定义事件
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
-->
<div id="app-8">
test7:
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
<script>
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')
}
},
})
new Vue({
el: '#app-8',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
</script>
<!--test8:给组件绑定原生事件-->
<!--有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用 v-on 的修饰符 .native。-->
<!--例如-->
<my-component v-on:click.native="doTheThing"></my-component>
<!--test9:自定义事件的表单输入组件-->
<!--简单的货币过滤器-->
<div id="app-9">
test9:<currency-input v-model="price"></currency-input>
</div>
<script>
Vue.component('currency-input', {
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
props: ['value'],
methods: {
// 不是直接更新值,而是使用此方法来对输入值进行格式化和位数限制
updateValue: function (value) {
var formattedValue = value
// 删除两侧的空格符
.trim()
// 保留 2 位小数
.slice(
0,
value.indexOf('.') === -1
? value.length
: value.indexOf('.') + 3
)
// 如果值尚不合规,则手动覆盖为合规的值
if (formattedValue !== value) {
this.$refs.input.value = formattedValue
}
// 通过 input 事件带出数值
this.$emit('input', Number(formattedValue))
}
}
})
new Vue({
el: '#app-9'
})
</script>
<!--test10:复杂的货币过滤器-->
test10:
<div id="app-10">
<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>
<script>
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) {
// Workaround for Safari bug
// http://stackoverflow.com/questions/1269722/selecting-text-on-focus-using-jquery-not-working-in-safari-and-chrome
setTimeout(function () {
event.target.select()
}, 0)
}
}
})
new Vue({
el: '#app-10',
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)
}
}
})
</script>
</body>
</html>