组件和组件通信
过滤器和自定义指令 (不重要)
某些情况下,可以通过过滤器来代替watch。
例如:数据的原有格式和渲染到视图上的格式不一致时,可以使用过滤器。
toUpperCase的参数就是管道符号前面表达式msg
如果一个数据要显示的格式需要更改,应该使用过滤器
<input type='text' v-model='msg' />
// 原始数据是msg,通过过滤规则toUpperCase进行转换后显示到视图上是全大写的msg.
<div>{{msg | toUpperCase}}</div>
new Vue({
el:'#app',
data:{
msg:''
},
filters:{
toUpperCase(val){
return val.toUpperCase()
}
}
})
自定义指令
封装自己的DOM操作(封装一些ui框架)
配置项directives
函数(标签,binding),binding.value是自定义指令的值
<div id='app'>
<div v-color='color'>111</div>
</div>
new Vue({
el: '#app',
data: {
color: 'green'
},
directives: {
// 第一个参数是绑定了自定义指令的标签。
// 第二个参数是当前指令的一些信息.
// config.value就是自定义指令的值.
color(el, config) {
el.style.backgroundColor = config.value
}
}
})
组件
组件是为了复用布局和逻辑
每个组件都是一个Vue实例。
这就意味着,组件可以写所有的Vue构造选项。(除了el选项)
每个组件都有自己的 视图 和 数据。
=> 组件的视图用template来书写。组件的 template 必须有一个唯一的父元素。
=> 组件的数据用data来书写,组件的data必须写成一个函数,然后返回一个对象,这个对象内写组件数据。
data(){ return {数据}}
组件methods内的方法内的 this,默认指向当前组件。
组件注册
通过配置项components注册
分为局部注册(当前组件视图可用)
和全局组件(哪都能用)
// 函数要声明
// 组件要注册
const news = {
template: `
<div>
<h3>今天的新闻</h3>
<p>今天的新闻内容</p>
</div>
`
}
// 全局注册 => 哪里都能用news组件
Vue.component('news', news);
new Vue({
el: '#app',
// 注册一个叫news的组件
// 局部注册 => 只能在当前组件视图中使用.
components: { news }
})
组件命名
如果组件的名字是驼峰命名,挂载时需要把驼峰命名转换为带 – 的自定义标签名。
在components:{ newsView }
注册用驼峰命名
在组件挂载的时候使用需要转为<news-view />
组件挂载
如果需要在组件A中使用组件B,除了要通过components注册以外,还需要在A的视图内挂载B的视图。
视图挂载需要通过一个跟组件名相同的自定义标签来进行挂载。
挂载时,可以使用单标签也可以使用双标签,如果连续挂载两次,不能使用单标签。
如果组件的这个父元素需要v-for渲染.则应该把v-for写在组件挂载的地方.<news-view v-for='a in 3'></news-view>
<div id='app'>
<!-- 一个组件挂载了3次.挂载时可以用单标签,也可以用双标签. -->
<!-- 挂载时,如果组件名是带驼峰的,你需要挂载的时候加- -->
<!-- 挂载的最终结果就是挂载的标签被组件的template指定的布局替换 -->
<news-view></news-view>
<news-view></news-view>
<news-view></news-view>
</div>
<script>
const newsView = {
template: `
<div>
<h3>今天的新闻</h3>
<p>今天的新闻内容</p>
</div>
`
}
new Vue({
el: '#app',
components: { newsView }
})
</script>
根组件
new Vue创建的实例叫根实例,它用选项 el 指定的视图就是整个Vue程序的主视图。
这个 el 的 视图可以写在html的body内,其实也可以写在 new Vue的 template 选项里。
根实例有自己的视图,自己的数据,这时,可以把这个根实例封装成一个根组件。
const App = {
template:`
<div id='app'>
<p>{{msg}}</p>
</div>
`,
data(){
return {msg:'hello Vue'}
}
}
然后把这个组件注册到new Vue上
new Vue({
el:'#app',
template:`<App />`,
components:{App}
})
记住:
数据写在哪个组件的视图里,它就是哪个组件的数据。
子组件挂载在哪个组件的视图内,它就应该在哪个组件中注册。
组件通信
想要每次挂载都渲染不同的内容,可以在这个自定义标签上通过自定义属性来创建不同的渲染内容
然后子组件内通过props选项来声明对应的数据,这个数据名就是自定义标签上的自定义属性,
props声明的数据都是由父组件传递给子组件的数据
且props声明的数据不能再子组件中修改(这数据如果是基本类型,修改了,父组件的不变,子组件的变,但会报错。如果是引用类型,被修改了,则都变(没有修改引用))
props: ['msg', 'obj'],
methods: {
fn() {
//可以通过this访问props数据.
console.log(this.msg)
//报错
this.msg = Math.random();
//不报错.
this.obj.name = '超越';
//报错.不能修改obj本身
this.obj = 10000;
}
props父传子
Vue => 单向数据流 => 从上往下的.(不能自下而上)
父组件数据变化 => 父组件视图更新 => :msg=’msg’重新执行 => 新的msg的值传递给了子组件 => 子组件msg变化 => 子组件视图更新
如果props的数据在赋值时,希望通过一个变量来赋值,则需要加:(v-bind)
直接赋值 day='今天'
变量赋值:day='day2'
const newsView = {
template: `
<div>
<h3>{{day}}的新闻标题</h3>
<p>{{day}}的新闻内容</p>
</div>
`,
// 声明一个props数据
props: ['day']
}
// 如果props的数据在赋值时,希望通过一个变量来赋值,则需要加:(v-bind)
const App = {
template: `
<div id='app'>
<news-view v-bind:day='day1'></news-view>
<news-view :day='day2'></news-view>
<news-view day='后天'></news-view>
</div>
`,
data() {
return {
day1: '今天',
day2: '明天',
day3: '后天',
}
},
components: { newsView },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
子传父
- 父组件需要一个方法(函数)来接收子组件数据
- 子组件触发父组件的这个方法,并传入子组件数据
子组件如何触发父组件的方法?
一、把父组件的方法传递给子组件触发(引用赋值传递)
const myComponent = {
template: `
<div>
<h3>子组件msg---{{msg}}</h3>
<button @click='fn'>按钮</button>
</div>
`,
props: ['getMsg'],
data() {
return {
msg: '子组件的msg'
}
},
methods: {
fn() {
// 调用父组件方法,并传递子组件的数据.
this.getMsg(this.msg);
}
}
}
const App = {
template: `
<div id='app'>
<h3>App根组件msg--{{msg}}</h3>
<!--父组件方法传递给子组件-->
<myComponent :getMsg='getMsg' />
</div>
`,
data() {
return {
msg: '',
}
},
methods: {
// 父组件用于接收子组件的方法。
getMsg(msg) {
this.msg = msg;
}
},
components: { myComponent },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
二、自定义事件实现(给子组件绑定一个自定义事件,这个自定义事件触发时调用父组件的方法)
父组件把接收msg方法传给自定义事件myevent <myComponent @myevent='getMsg' />
子组件 <button @click='fn'>按钮</button>
,
methods: {
fn() {
// $emit => 主动触发事件.
// 第一个参数是事件名, 第二个参数是传递给事件句柄的参数
this.$emit('myevent', this.msg);
}
}
const myComponent = {
template: `
<div>
<h3>子组件msg---{{msg}}</h3>
<button @click='fn'>按钮</button>
</div>
`,
data() {
return {
msg: '子组件的msg'
}
},
methods: {
fn() {
// $emit => 主动触发事件.
// 第一个参数是事件名, 第二个参数是传递给事件句柄的参数
this.$emit('myevent', this.msg);
}
}
}
const App = {
template: `
<div id='app'>
<h3>App根组件msg--{{msg}}</h3>
<!--给子组件绑定一个myevent自定义事件,这个自定义事件的事件句柄是getMsg-->
<myComponent @myevent='getMsg' />
</div>
`,
data() {
return {
msg: '',
}
},
methods: {
// 父组件用于接收子组件的方法。
getMsg(msg) {
this.msg = msg;
}
},
components: { myComponent },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
如何在子组件修改父组件数据
- 把修改数据的逻辑方法写在父组件数据上
- 在子组件中触发父组件方法(子传父)
const myComponent = {
template: `
<div>
<h3>子组件msg---{{msg}}</h3>
<button @click='show'>按钮</button>
</div>
`,
props: ['fn', 'msg'],
methods: {
show() {
this.fn(Math.random());
}
}
}
const App = {
template: `
<div id='app'>
<h3>App根组件msg--{{msg}}</h3>
<myComponent :fn='fn' :msg='msg' />
</div>
`,
data() {
return {
msg: '父组件的数据msg',
}
},
methods: {
// 用fn修改父组件的msg数据 => 这样父子组件可以同时更新。
// 只要让子组件能够触发父组件的这个fn.就可以实现子组件修改父组件的数据.
fn(msg) {
this.msg = msg
}
},
components: { myComponent },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
const myComponent = {
template: `
<div>
<h3>子组件msg---{{msg}}</h3>
<button @click='show'>按钮</button>
</div>
`,
props: ['msg'],
methods: {
show() {
this.$emit('myevent', Math.random())
}
}
}
const App = {
template: `
<div id='app'>
<h3>App根组件msg--{{msg}}</h3>
<myComponent @myevent='fn' :msg='msg' />
</div>
`,
data() {
return {
msg: '父组件的数据msg',
}
},
methods: {
// 用fn修改父组件的msg数据 => 这样父子组件可以同时更新。
// 只要让子组件能够触发父组件的这个fn.就可以实现子组件修改父组件的数据.
fn(msg) {
this.msg = msg
}
},
components: { myComponent },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})