一、 过滤器
1.0
<body>
<div id='app'>
<div v-color='color'>111</div>
</div>
</body>
指令 => 封装DOM操作
自定义指令 => 封装自己的DOM操作(封装一些ui框架特别有用)
v-color='red' => DOM操作把当前标签设置为背景红
<script src="js/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
color: 'green'
},
directives: {
// 第一个参数是绑定了自定义指令的标签。
// 第二个参数是当前指令的一些信息.
// config.value就是自定义指令的值.
color(el, config) {
el.style.backgroundColor = config.value
}
}
})
</script>
1.1
<body>
<div id='app'>
<input type="text" v-model='msg'>
<div>{{msg | money}}</div>
</div>
</body>
如果一个数据要显示的格式需要更改,应该使用过滤器
| => 管道符.(angular).
<script src="js/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
msg: ''
},
// 过滤器.val形参就是 | 前面的表达式的值.
filters: {
money(val) {
let re = /\B(?=((\d{3})+$))/g;
return val.replace(re, ',');
}
}
})
</script>
二、自定义指令
<body>
<div id='app'>
<div v-color='color'>111</div>
</div>
</body>
指令 => 封装DOM操作
自定义指令 => 封装自己的DOM操作(封装一些ui框架特别有用)
v-color='red' => DOM操作把当前标签设置为背景红
<script>
new Vue({
el: '#app',
data: {
color: 'green'
},
directives: {
// 第一个参数是绑定了自定义指令的标签。
// 第二个参数是当前指令的一些信息.
// config.value就是自定义指令的值.
color(el, config) {
el.style.backgroundColor = config.value
}
}
})
</script>
三、组件
<body>
<div id='app'>
<news></news>
<news></news>
<news></news>
</div>
</body>
函数为什么要封装?
复用相同的逻辑和代码.组件都是vm实例.它可以有自己的视图,自己的数据,自己的逻辑.
组件是为了复用布局以及逻辑.
<script>
new Vue({
el: '#app',
components: {
news: {
template: `
<div>
<h3>今天的新闻</h3>
<p>今天的新闻内容</p>
</div>
`
}
}
})
</script>
四、组件注册
<body>
<div id='app'>
<news></news>
<news></news>
<news></news>
</div>
</body>
<script src="js/vue.js"></script>
<script>
// 函数要声明
// 组件要注册
const news = {
template: `
<div>
<h3>新闻</h3>
<p>新闻内容</p>
</div>
`
}
// 全局注册 => 哪里都能用news组件
Vue.component('news', news);
new Vue({
el: '#app',
// 注册一个叫news的组件
// 局部注册 => 只能在当前组件视图中使用.
components: { news }
})
</script>
五、组件命名
<body>
<div id='app'>
<!-- 组件挂载时,大写都会变小写 -->
<news-view></news-view>
<news-view></news-view>
<news-view></news-view>
</div>
</body>
<script src="js/vue.js"></script>
<script>
// 函数要声明
// 组件要注册
const newsView = {
template: `
<div>
<h3>新闻</h3>
<p>新闻内容</p>
</div>
`
}
new Vue({
el: '#app',
// 组件名如果是驼峰命名,需要在引用组件时,添加-
// components: { newsView }
components: { "news-view": newsView }
})
</script>
六、组件的挂载
一个组件挂载了3次.挂载时可以用单标签,也可以用双标签.
挂载时,如果组件名是带驼峰的,你需要挂载的时候加
挂载的最终结果就是挂载的标签被组件的template指定的布局替换
<body>
<div id='app'>
<news-view></news-view>
<news-view></news-view>
<news-view></news-view>
</div>
</body>
<script src="js/vue.js"></script>
<script>
// 函数要调用
// 组件要挂载(组件的引用)
const newsView = {
template: `
<div>
<h3>今天的新闻</h3>
<p>今天的新闻内容</p>
</div>
`
}
new Vue({
el: '#app',
components: { newsView }
})
</script>
七、组件的选项
一个组件挂载了3次.挂载时可以用单标签,也可以用双标签.
挂载时,如果组件名是带驼峰的,你需要挂载的时候加-
挂载的最终结果就是挂载的标签被组件的template指定的布局替换
<body>
<div id='app'>
<news-view></news-view>
<news-view></news-view>
<news-view></news-view>
</div>
</body>
newsView是组件的配置项.
template是组件的布局选项.(写组件的视图用的)
组件都是vue实例.可以写任意的Vue选项.除了el选项(例如data,methods,computed,filter,components...)组件的选项和new Vue的选项区别:
1:不用el选项.(写了没意义).
2:data必须写成函数.把数据对象return出来.
<script src="js/vue.js"></script>
<script>
const newsView = {
template: `
<div>
<h3 @click='fn'>{{title}}</h3>
<p>今天的新闻内容</p>
</div>
`,
data() {
return {
title: '今天的新闻'
}
},
methods: {
fn() {
alert(this.title)
}
}
}
new Vue({
el: '#app',
components: { newsView },
})
</script>
八、组件的组件
<body>
<div id='app'>
<news-view></news-view>
<news-view></news-view>
<news-view></news-view>
</div>
</body>
组件都是vue实例,隐藏它也可以写components选项
在newsView中注册了box组件。
newsView就是box的父组件.
box组件就是newsView的子组件.
box组件和son组件是兄弟组件.哪个组件的视图使用了数据,就在哪个组件内声明这个数据
哪个组件的视图挂载了其他组件A,就在哪个组件内声明这个A组件
<script src="js/vue.js"></script>
<script>
const box = {
template: `<button>box组件的按钮</button>`
}
const son = {
template: `<span>son组件</span>`
}
const newsView = {
template: `
<div>
<h3 @click='fn'>{{title}}</h3>
<p>今天的新闻内容</p>
<box />
<box />
<box />
<son />
</div>
`,
data() {
return {
title: '今天的新闻'
}
},
methods: {
fn() {
alert(this.title)
}
},
components: { box, son }
}
new Vue({
el: '#app',
components: { newsView },
})
</script>
九、v-for和组件
body>
<div id='app'>
<news v-for='d in 3'></news>
<div>
<div>
<section>
<news v-for='d in 3'></news>
</section>
</div>
</div>
<footer>
<news v-for='d in 3'></news>
</footer>
</div>
</body>
组件的template内必须有一个唯一的父元素包裹所有的布局.
如果组件的这个父元素需要v-for渲染.则应该把v-for写在组件挂载的地方.
<script src="js/vue.js"></script>
<script>
const news = {
template: `
<div>
<h3 @click='fn'>{{title}}</h3>
<p>今天的新闻内容</p>
</div>
`,
data() {
return {
title: '今天新闻'
}
},
methods: {
fn() {
alert(9090)
}
},
}
new Vue({
el: '#app',
components: { news }
})
</script>
十、父传子props
<body>
<div id='app'>
<news-view day='今天'></news-view>
<news-view day='明天'></news-view>
<news-view day='后天'></news-view>
</div>
</body>
组件数据
1:data数据(一般数据)
2:计算属性数据.
3:props数据.(父传子数据)
<script src="js/vue.js"></script>
<script>
const newsView = {
template: `
<div>
<h3>{{day}}新闻标题</h3>
<p>{{day}}新闻内容</p>
</div>
`,
// 声明一个props数据
props: ['day']
}
new Vue({
el: '#app',
components: { newsView },
})
</script>
十一、根组件
template => 为了指定视图。
el => 为了挂载视图
组件可以写template选项.
new Vue时可以写吗?new Vue时,如果没有写template选项,则vue会使用el所在的标签作为视图。
根组件. => 所有组件的唯一祖先组件。
1.0
<!-- 挂载点 -->
<span id='app'></span>
<script src="js/vue.js"></script>
<script>
const App = {
template: `
<div id='app'>
<h3>App根组件--{{day}}</h3>
</div>
`,
data() {
return {
day: '今天'
}
}
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
});
</script>
new Vue({
el: '#app',
template: `
<div id='app'>
<h3>App根组件--{{day}}</h3>
</div>
`,
data: {
day: '今天'
}
});
1.1
<body>
<div id='app'></div>
</body>
完成以上计算总价的效果.
分别用计算属性和watch实现.
<script src="../js/vue.js"></script>
<script>
const App = {
template: `
<div id='app'>
<input type="text" placeholder="单价" v-model='price'>
<input type="text" placeholder="数量" v-model='count'>
<div>总价:{{total}}</div>
</div>
`,
data() {
return {
price: 10,
count: 1
}
},
computed: {
total() {
return this.price * this.count
}
}
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
</script>
十二、props父传子
<body>
<div id="app"></div>
</body>
1.0
<script src="js/vue.js"></script>
<script>
const newsView = {
template: `
<div>
<h3>{{day}}的新闻标题</h3>
<p>{{day}}的新闻内容</p>
</div>
`,
// 声明一个props数据
props: ['day']
}
const App = {
template: `
<div id='app'>
<news-view day='今天'></news-view>
<news-view day='明天'></news-view>
<news-view day='后天'></news-view>
</div>
`,
components: { newsView },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
</script>
1.1
如果props的数据在赋值时,希望通过一个变量来赋值,则需要加:(v-bind)
子组件数据 => day
父组件数据 => day1,day2,day3
子组件在挂载时,子组件数据被父组件数据赋值.(父传子)父传子 => 让子组件复用时渲染了不同的内容(数据).
插槽 => 让子组件复用时,渲染不同的标签.父传子 => 前子后父.
<script src="js/vue.js"></script>
<script>
const newsView = {
template: `
<div>
<h3>{{day}}的新闻标题</h3>
<p>{{day}}的新闻内容</p>
</div>
`,
// 声明一个props数据
props: ['day']
}
const App = {
template: `
<div id='app'>
<news-view v-bind:day='day1'></news-view>
<news-view :day='day2'></news-view>
<news-view :day='day3'></news-view>
</div>
`,
data() {
return {
day1: '今天',
day2: '明天',
day3: '后天',
}
},
components: { newsView },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
</script>
1.2
Vue => 单向数据流 => 从上往下的.(不能自下而上)
父组件数据变化 => 父组件视图更新 => :msg='msg'重新执行 => 新的msg的值传递给了子组件 => 子组件msg变化 => 子组件视图更新
在子组件中,是不能修改父组件传递的props数据.
但是可以操作应用类型的数据.
如果传递的是一个引用类型,则传递的是这个引用类型的引用.
我们不能在子组件中修改这个引用,但是可以修改这个引用背后的对象.
这样做修改的对象其实是父组件的对象,会导致父组件和子组件同时更新.
<script src="js/vue.js"></script>
<script>
const myComponent = {
template: `
<div>
<h3>子组件msg---{{msg}}</h3>
<h3>子组件obj---{{obj.name}}</h3>
<button @click='fn'>按钮</button>
</div>
`,
props: ['msg', 'obj'],
methods: {
fn() {
// 可以通过this访问props数据.
// console.log(this.msg)
// 报错
// this.msg = Math.random();
// 不报错.
// this.obj.name = '超越';
// 报错.不能修改obj本身
// this.obj = 10000;
}
}
}
const App = {
template: `
<div id='app'>
<h3>App根组件msg--{{msg}}</h3>
<h3>App根组件obj--{{obj.name}}</h3>
<myComponent :msg='msg' :obj='obj' />
<button @click='fn'>父按钮</button>
</div>
`,
data() {
return {
msg: '父组件的数据msg',
obj: { name: '幂幂' },
}
},
methods: {
fn() {
this.msg = Math.random();
}
},
components: { myComponent },
}
new Vue({
el: '#app',
template: `<App />`,
components: { App }
})
</script>
十三、子传父
<body>
<div id='app'></div>
</body>
1.0
子传父:
1:父组件需要一个方法来接收子组件数据.
2:子组件触发父组件的这个方法.并传入子组件数据.子组件如何触发父组件的方法?
1:把父组件的方法传递给子组件触发.(引用赋值传递)
<script src="js/vue.js"></script>
<script>
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 }
})
</script>
1.2
子传父:
1:父组件需要一个方法来接收子组件数据.
2:子组件触发父组件的这个方法.并传入子组件数据.子组件如何触发父组件的方法?
1:把父组件的方法传递给子组件触发.(引用赋值传递)
2:自定义事件实现.(给子组件绑定一个自定义事件,这个自定义事件触发时调用父组件的方法)
<script src="js/vue.js"></script>
<script>
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 }
})
</script>
十四、如何在子组件修改父组件数据
<body>
<div id='app'></div>
</body>
子组件修改父组件的数据
1:把修改数据的逻辑方法写在父组件上.
2:在子组件中触发父组件的方法.(子传父)
<script src="js/vue.js"></script>
<script>
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 }
})
</script>
十五、如何子组件修改父组件数据
<body>
<div id='app'></div>
</body>
子组件修改父组件的数据
1:把修改数据的逻辑方法写在父组件上.
2:在子组件中触发父组件的方法.(子传父)
<script src="js/vue.js"></script>
<script>
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 }
})
</script>