https://github.com/fishenal/vuejs-demo-project
项目地址:https://github.com/fishenal/vuejs-demo-project
layout布局
先构造出layout,把布局写好。
页头
由登陆注册关于退出构成,维护了一个username变量,如果登陆成功username被赋值,退出就会显示,按下退出,username就会被销毁。
弹框的实现
首先实现了最基本的弹窗布局,封装在dialog组件之中,可以传递isShow变量决定是否显示,通过发射onclose事件告诉父亲是否要关闭。
接着在dialog中引入logform组件实现登陆框布局,这是一个表单,它包括表单绑定的数据变量以及错误提示变量errorText
表单中值得注意的是使用了计算属性去验证表单字段
1234567891011121314151617181920 > userErrors () {> let errorText, status> if (!/@/g.test(this.usernameModel)) {> status = false> errorText = '不包含@'> }> else {> status = true> errorText = ''> }> if (!this.userFlag) {> errorText = ''> this.userFlag = true> }> return {> status,> errorText> }> },>
usererror随着model字段变化而变化,同时显示在表单末尾。因为它是子组件,所以在按下登陆的时候,需要发射一个has-log事件并把表单字段传递给父亲。
layout中对弹窗的控制
功能都在组件中实现了,那么layout就只要控制弹窗的显示与隐藏,只需要将isShow与各自显示控制字段绑定即可。
组件路由
layout.vue中
1234 > <keep-alive>> <router-view></router-view>> </keep-alive>>
实现路由到不同的页面
index页面
数据填充
在创建的时候就通过请求获取数据
123456789 > created: function () {> this.$http.get('api/getNewsList')> .then((res) => {> this.newsList = res.data> }, (err) => {> console.log(err)> })> },>
然后利用for循环将数据装入
12345678910111213 > <div> class="index-board-item"> v-for="(item, index) in boardList"> :class="[{'line-last' : index % 2 !== 0}, 'index-board-' + item.id]">> <div class="index-board-item-inner" >> <h2>{{ item.title }}</h2>> <p>{{ item.description }}</p>> <div class="index-board-button">> <router-link class="button" :to="{path: 'detail/' + item.toKey}">立即购买</router-link>> </div>> </div>> </div>>
这段特别之处在于循环中使用变量来控制class,也就是说可以利用表达式构造自定义的class从而实现不同的css效果,上述代码借此实现奇偶项margin的不同以及不同块背景背景的不同。
轮播图组件
轮播图组件实现的核心是使用一个nowindex变量控制哪一张显示以及isShow属性控制css动画。有一个runinv方法定时切换以及一个clearinv当鼠标悬停时不轮播切换。同时,它可以接收父元素给的inv和图像。
detail页面
左边列表栏
利用v-for循环插入,特别之处在于active-class的绑定,这个可以指明选定该链接时应有的样式。
1234 > <router-link v-for="item in products" :to="{ path: item.path }" tag="li" active-class="active">> {{ item.name }}> </router-link>>
同时列表上方的图像也要根据不同的url而改变,所以建立了一个 url到图像的map
1234567 > imgMap: {> '/detail/count': require("../assets/images/1.png"),> '/detail/forecast': require("../assets/images/2.png"),> '/detail/analysis': require("../assets/images/3.png"),> '/detail/publish': require("../assets/images/4.png")> }>
同时控制图像显示的计算属性也会跟着url变化而变化
1234 > productIcon () {> return this.imgMap[this.$route.path]> }>
同时也要修改route的路由,这是一个嵌套的路由
12345678910111213141516171819202122232425262728293031323334353637 > let router = new VueRouter({> mode: 'history',> routes: [> {> path: '/',> component: IndexPage> },> {> path: '/orderList',> component: OrderListPage> },> {> path: '/detail',> component: DetailPage,> redirect: '/detail/analysis',> children: [> {> path: 'analysis',> component: DetailAnaPage> },> {> path: 'count',> component: DetailCouPage> },> {> path: 'forecast',> component: DetailForPage> },> {> path: 'publish',> component: DetailPubPage> }> ]> }> ]> })>
单选,多选与下拉组件
都是由now-index控制状态,最终发射onchange事件将数据传给父亲。
12345 > onParamChange (attr, val) {> this[attr] = val> this.getPrice()> },>
在父组件中这样赋值写的有点像表单了,这样可以实时更新选到的数据类似v-model.
checkOrder组件
这个组件思想和上面类似,注意之处是点击完成后的路由跳转
1234 > toOrderList () {> this.$router.push({path: '/orderList'})> }>
总结
Vue的思想有两个
MVVM
Vue将事件监听以及dom操作都封装到ViewModel里面去了,将视图和控制分离,实现了双向绑定,所以我们不需要直接操作dom,只要对数据进行控制。这意味着我们要把编程重心放在如何绑定变量,如何绑定事件,如何写v-for循环控制,如何写v-if条件控制上,以及将需要实时改变的数据写入watch或者computed。用变量来表征dom的状态。
组件化
一个页面根据布局进行拆分,父组件调用子组件就像函数调用一样,可以传递参数(利用prop),子组件像函数一样可以return一个变量(利用事件发射)。同时,使用vue-router可以将页面同一个地方展示不同的组件,从而做到页面切换的效果。
扩展
该项目中vuex使用
利用vuex可以把那些异步请求写在store里面,vux维护了一个state,我们只要调用getters获取状态即可
1234 > tableData () {> return this.$store.getters.getOrderList> }>
每一次需要ajax更新数据源时,只要分发 一个action
1234567 > this.$store.commit('updateParams', {> key: 'startDate',> val: date> })> this.$store.dispatch('refreshList')> },>