Vue 组件 / 杂项
2018-03-20 本文已影响3人
羊烊羴
利用v-model实现自定义的表单组件
在vue中,表单都可以使用v-model来实现双向数据绑定,看着v-model很神奇,但实际上这是一个vue的语法糖(语法糖指并没有实际为计算机语法添加新东西,只是使语法对于阅读和使用的人来说更加容易理解),v-model实际是以下方式的简写
<input
v-bind:value="something"
v-on:input="something=$event.target.value"
>
如果能够理解了上面的写法,那么我们就可以自己实现一个v-model的表单组件
<custom-input
v-bing:value='something'
v-on:input="something=arguments[0]">
</custom-input>
这个组件想要生效那么需要有两个必要的条件
- 接受一个value属性
- 在有新的值的时候触发input事件
<body>
<div id="box">
<h4>利用v-model实现自定义的表单组件</h4>
<h6>CounterBtn组件的值<s>{{btnValue}}</s></h6>
<counter-btn v-model='btnValue'></counter-btn>
<!--
v-model='btnValue'
相当于
:value="btnValue"
@input="btnValue=argument[0]"
子组件中的$emit()发送的事件必须命名为input,因为在v-model中存在@input会自动接收
而argument[0]可以理解为一种简写,
在我们通常写的父组件接收子组件发送的数据的写法是在方法中的参数就是子组件的数据
所以argument[0]也就是获取的子组件的$emit发送的数据中的data
这样的话我们就相当于
在我们的子组件中的input事件被触发的时候会发送数据到父组件,父组件在接收到数据后在更新自身的数据
相当于实现了v-model
-->
<form>
<labek for="count">绑定值到input隐藏域中</labek>
<input type="text" name="count" :value="btnValue.res" id="count">
<!--一般情况下input会被设置为type为hidden-->
</form>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
data:{
btnValue:{}
},
components:{
'counter-btn':{
template:`
<div class="coutter-wrapper">
<button type="button" @click="plus">+</button>
<button type="button">{{result}}</button>
<button type="button" @click="minus">-</button>
</div>
`,
methods:{
minus(){
this.result--;
this.$emit('input',{res:this.result,other:'--'})
},
plus(){
this.result++;
this.$emit('input',{res:this.result,other:'++'})
}
},
data(){
return{
result:0
}
}
}
}
}).$mount('#box')
</script>
</body>
is
<body>
<div class="box">
<table>
<!--<tem></tem>-->
<tr is="tem"></tr>
</table>
<!--如果没有使用模板方式,需要注意在ul,ol,table这些元素中放入组件不会被渲染,如例子中的tem虽然内容显示了,但并不是被渲染在table内,需要使用is的写法-->
</div>
<script>
Vue.component('tem', {
template: `
<h3>全局组件</h3>
`
})
new Vue({}).$mount(".box")
</script>
</body>
子组件索引(ref)
在组件中有时我们需要在javascript中直接访问子组件。为此我们可以使用ref为子组件指定一个索引ID,由此来获得组件内的参数,数据等内容
<body>
<template id="temp">
<h3>模板</h3>
</template>
<div id="box" @click="click">
<tem ref="demo"></tem>
<p ref="txt">
Lorem ipsum dolor sit amet, consectetur.
</p>
</div>
<script>
Vue.component(
"tem", {
template: "#temp",
data: function () {
return {
msg: "模板的数据"
}
},
methods:{
show(){
return "模板的show方法"
}
}
}
)
new Vue({
el: "#box",
methods: {
click: function () {
console.log(this.$refs.demo.msg); //模板的数据
console.log(this.$refs.demo.show()); //模板的show方法
console.log(this.$refs.txt.innerText); //Lorem ipsum dolor sit amet, consectetur.
}
}
})
</script>
</body>
当ref和v-for一起使用的时候,ref是一个数组,数组内包含对应的子组件
需要特别注意的是ref只在组件渲染完成后才能填充,并且ref并不是响应式的
异步组件
在页面载入的时候,我们有时候不需要一次性的将所有的组件全部载入,尤其是当一些组件是需要在被触发才需要显示的情况,一次性全部加载会让我们第一次加载的文件变大,拖慢我们的搜词加载速度,所以我们需要用到异步组件
<div id="box">
<p>{{msg}}</p>
<async></async>
</div>
<script>
Vue.component('async', function (resolve, reject) {
setTimeout(function () {
// 将组件定义传入 resolve 回调函数
resolve({
template: '<div>我会在setimeout执行完成后显示</div>'
})
}, 1000)
})
new Vue({
el: "#box",
data: {
msg: "正常展示会在页面加载完成时显示"
}
})
</script>
</body>
vue允许我们为组件定义一个工厂函数,使用promise,在需要的时候触发工厂函数渲染,并且会将结果存储起来,用于后面的再次渲染,这里的settimeout只是为了示例效果,我们可以根据实际开发需要定义触发resolve的条件
如果我们想要所有的组件都是异步加载的,那么可以采用下面两种写法
new Vue({
//...
components:{
Banner: () => ({
component: import("components/Banner")
})
}
})
const Banner= Vue.component("Slider", resolve=>{
require(['../Slider.vue'], resolve)
})
高级异步组件
自 2.3.0 起,异步组件的工厂函数也可以返回一个如下的对象:
const AsyncComp = () => ({
// 需要加载的组件。应当是一个 Promise
component: import('./MyComp.vue'),
// 加载中应当渲染的组件
loading: LoadingComp,
// 出错时渲染的组件
error: ErrorComp,
// 渲染加载中组件前的等待时间。默认:200ms。
delay: 200,
// 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
timeout: 3000
})
注意,当一个异步组件被视作为vue-router的路由使用时,这些高级选项都是无效的,因为切换路由前就会提前加载所需的异步组件。另外,如果要在路由组件中使用改写法,需要vue-router2.4.0以上版本