理一下基于Vue3.0商城页面的开发思路。是基于Js+Vue+大厂面试这里的视频写的。
1. 组件基本嵌套思想:
2. MALL组件中的导航部分样式动态改变:
通过一个组件数据current
表示当时选中的导航项的名称,为每个导航项注册点击事件
以“手机”为例:<a :class = "{active: this.current == '手机' @click = changeClass('手机')}">手机</a>
methods:{
changeClass(c){
this.current = c
}
}
同时,由于a标签有默认事件,可通过<a :class = "{active: this.current == '手机' @click.prevent = changeClass('手机')}">手机</a>
的方法阻止默认事件,解决点击a标签时的页面闪烁问题。
3. 展示列表组件中的内容如何根据导航变化——计算属性computed
假设我们已经在MALL组件中,获取到了所有项的数据列表items
,items
中的每一项都有classfication
属性,由于我们需要从已知的数据中过滤数据,这时要想到computed
计算属性。
MALL组件中:
computed: {
showItems: {
get () {
let items = this.items
if (this.current != ''){
items = this.items.filter(item => item.current == this.current)
}
return items
}
}
}
在MALL组件中:<show-list :dataList = showItems/>
在展示列表组件中接收:props: ['dataList']
,然后在展示列表组件中就可以使用dataList
数据,就相当于这个组件的data
函数中已经有了dataList
(个人理解哈)
4. 分页组件
- 思考这个子组件需要接收哪些数据(
props
):
total
(总的数据量)
prepage
(每一页显示的数量)
page
(当前页码)
由此我们可得出总的页数:
pages: Math.ceil( this.total / this.prepage)
将总页数pages
放在computed
中,而不能放在data
中,因为做到这里,展示列表组件中展示的数据是根据导航栏的不同分类展示了全部,并没有根据页码分页,如果放在data
中,只会在页面刚开始渲染的时候计算一次pages
的值,后面点击其他分类时,实际上total
的值已经改变为新的类别下的总数量,但data
中不会再重新实时更新计算了,因此需要放入computed
中以达到每次点击不同分类都能更新total
,从而更新pages
。 - 基本template模板:
<a>上一页</a>
<a v-for = "p of pages">{{p}}</a>
<a>下一页</a>
这里注意,v-for
是可以遍历数组,对象和数字的。
- 当前页码高亮处理:
可以通过动态class属性绑定:
<a >上一页</a>
<a :class = "{current: p == page}" v-for = "p of pages">{{p}}</a>
<a>下一页</a>
- 上一页、页码、下一页的点击事件处理:
<a @click.prevent = "changePage(page - 1)">上一页</a>
<a :class = "{current: page == p}" v-for = "p of pages" @click.prevent = "changePage(p)">{{p}}</a>
<a @click.prevent = "changePage(page + 1)">下一页</a>
第一想法必然是在分页组件的methods
中写changePage
函数:
methods: {
changePage(p){
this.page = p
}
}
但这是错误的! 因为page
这个数据是用props
接收的,所以这是父组件(展示列表组件)中的数据。如果我们直接在子组件中修改了这个数据,父组件并没有同步到,在父组件中很有可能还有其他的子组件用到这个数据。因此,我们必须要让父组件去修改这个数据,然后子组件就可以通过props
接收到它的变化。
那么父组件如何修改呢?可通过$emit事件
的方式,在子组件中触发事件,父组件中接收到事件信号,修改数据。
分页子组件中:
methods: {
changePage(p){
this.$emit("changePage", p)
}
}
展示列表父组件中(不同类别下的各自总数量上面已经说过了,是接受了MALL组件传入的dataList
数据):
<k-pagination :pages = dataList.length :perpage = prepage :page = page :changePage = "change"/>
methods: {
change(p){
this.page = p
}
}
这样就在父组件中修改了page
,会自动通过props
传送到子组件中同步修改。、
- 展示列表组件中根据页码显示不同的项
展示列表组件中:
<ul>
<li v-for = "item of listItems">...(具体不详细写了)</li>
</ul>
computed: {
listItems: {
get () {
let start = (this.page - 1) * this.prepage
let end = start + this.prepage
return this.dataList.slice(start, end)
}
}
}
5. 购物车组件
- 购物车组件显示:
展示列表k-items
组件下,点击导航栏中的购物车后就显示购物车组件内容,说明展示列表组件和购物车组件不同时显示,我们可以用动态组件的方法切换这两个组件:<component :is="currentView"></component>
,is绑定的值是组件名称,可为导航注册点击事件,改变currentView
的值,展示列表组件k-items
和购物车k-carts
这两个组件中所需要绑定的数据和方法都可以直接写在component
这一个组件中即可。 - 选中
当购物车中的任意一个项被选中时,需要将这个项的checked
属性变为true
,又要改变通过props
接收的数据,可为这个单选框控件绑定change
事件,<input @change = "changeChecked(item, $event)" />
,k-carts
组件中的changeChecked
方法为:
methods: {
changeChecked(item, e){
this.$emit("changechecked", item, e.target.checked)
}
}
k-items
组件中,<component :is="currentView" :changechecked = “changeChecked”></component>
,并在此组件的changeChecked
方法中,将该项的checked
属性变为true
。
- 全选和反选
双向绑定全选控件<input v-model = "checkedall"/>
,通过v-model
实现数据的双向流动。这里由于checkedall
是k-carts
组件内部自身的数据,因此可以双向绑定。(但如果是要改变通过props
接收的数据,子组件是不能擅自修改的,必须通过$emit
通过父组件去修改)
k-carts
组件中:
computed: {
checkedall: {
//get函数用来实现自动全选:当每一项的checked为true时,全选按钮就自动选中
get () {
return this.cartItems.every(ci => ci.checked)
},
//set函数实现手动全选:监视当前属性值的变化,当属性值发生变化时执行,更新相关的属性数据
set (newVal) {
return this.$emit("changeall", newVal)
}
}
}
k-items
组件中:
<component :is="currentView" :changechecked = “changeChecked” :changeall = "changeAll"></component>
methods: {
changeAll(item, checked){
this.cartItems.forEach(ele => {
ele.checked = checked
})
}
}