12

433 阅读7分钟

VUE项目-第十二天

01-反馈

姓名 意见或建议
*** Promise和async同为发送请求的异步操作是如何区分以及使用的?萌
*** 不知道axios.defaults.baseURL的值和接口文档中的接口基准地址是什么关系?

  • Promise async await 处理异步操作
    • 只是写法不一样
    • Promise 在处理异步操作的时候 还是需要使用 then catch 还不是特别方便
    • async await 方便我们在做异步操作的时候 写法可以是同步写法 逻辑清晰
  • axios.defaults.baseURL

02-回顾

- 写代码

03-商品添加-组件基础布局

  • 面包屑

  • 卡片

  • 警告条

  • 步骤条

  • tab标签页

  • 效果:切换tab的时候同时去切换步骤条

    基本信息 商品参数 商品属性 商品图片 商品内容

    changeTab (tab) { // 根据当去的tab的位置 去切换步骤条的位置 // tab 当请点击的tab的实例对象 包含一些信息 // console.log(tab) tab.index 就是索引正好对应 步骤条的active数据 this.active = +tab.index }

    data () { return { // 是当前步骤的索引 active: 0 } },

04-商品添加-表单准备及验证

表单的基础布局:

<el-form ref="form" :model="form" :rules="rules" label-width="200px" autocomplete="off">
  <el-form-item label="商品名称" prop="goods_name">
    <el-input v-model="form.goods_name" style="width: 400px"></el-input>
  </el-form-item>
  <el-form-item label="商品分类" prop="goods_cat">
    <el-input v-model="form.goods_cat" style="width: 200px"></el-input>
  </el-form-item>
  <el-form-item label="商品价格" prop="goods_price">
    <el-input v-model="form.goods_price" style="width: 200px"></el-input>
  </el-form-item>
  <el-form-item label="商品数量" prop="goods_number">
    <el-input v-model="form.goods_number" style="width: 200px"></el-input>
  </el-form-item>
  <el-form-item label="商品重量" prop="goods_weight">
    <el-input v-model="form.goods_weight" style="width: 200px"></el-input>
  </el-form-item>
</el-form>

// 添加商品表单数据
form: {
  goods_name: '',
  goods_cat: '',
  goods_price: '',
  goods_number: '',
  goods_weight: '',
  goods_introduce: '',
  pics: [],
  attrs: []
},
rules: {
  goods_name: [
    {required: true, message: '商品名称必填', trigger: 'blur'}
  ],
  goods_cat: [
    {required: true, message: '商品分类必填', trigger: 'blur'}
  ],
  goods_price: [
    {required: true, message: '商品价格必填', trigger: 'blur'}
  ],
  goods_number: [
    {required: true, message: '商品数量必填', trigger: 'blur'}
  ],
  goods_weight: [
    {required: true, message: '商品重量必填', trigger: 'blur'}
  ]
}

实现分类级联功能:

<el-cascader
  clearable
  style="width: 200px"
  expand-trigger="hover"
  :options="categoryList"
  v-model="categoryValues"
  :props="{value:'cat_id',label:'cat_name'}"
  @change="handleChange">
</el-cascader>

// 级联相关的数据
categoryList: [],
categoryValues: []

handleChange () {
},
async getData () {
  // 获取三级分类数据  且赋值给级联组件
  const {data: {data, meta}} = await this.$http.get('categories')
  if (meta.status !== 200) return this.$message.error('获取分类数据失败')
  this.categoryList = data
}

实现表单校验:

  • 级联校验需要加上

    • 改成 change 事件去触发校验 文字提示该了一下

    • 因为校验的是 字段 form.goods_cat 而在选择级联的时候没有去修改这个字段

    • 选择级联的时候去修改这个字段 怎么去修改???

    • 思路:通过绑定事件去做 可以

    • 使用的方式:通过侦听器去监听 categoryValues 字段值改变 去修改 form.goods_cat

      watch: { categoryValues (now, old) { // 当 categoryValues 值改变的时候 // form.goods_cat 赋值 // 如果 categoryValues 的长度不等于3 就不赋值清空 if (now.length === 3) { // 以为','分割的分类列表 this.form.goods_cat = now.join(',') } else { this.form.goods_cat = '' // this.categoryValues = [] } } }

  • 离开第一个选项卡就该 对整个表单进行校验

    • 如果校验失败 阻止切换选项卡

    • 如果成功 放行

      changeTabBefore (activeName, oldActiveName) { console.log(activeName, oldActiveName) // 对整个表单进行校验 // 如果校验失败 阻止切换 // return false 即可阻止 必须在当前函数的作用域下有效 // return Promise 对象 执行 reject 阻止 if (oldActiveName === '0') { // 如果离开的是第一个选项卡 去做校验
      return new Promise((resolve, reject) => { this.$refs.form.validate(valid => { if (valid) { // 校验成功 随着tab的索引去切步骤条 this.active = +activeName resolve() } else { // 阻止切换
      reject(new Error('校验表单失败')) } }) }) } else { // 如果不是第一个选项 随着tab的索引去切步骤条 this.active = +activeName } }

05-商品添加-渲染参数及属性

  • 参数及属性数据 需要请求两次去获取不同的属性列表数据

    // id 当前选中的第三级分类的ID const {data: {data, meta}} = await this.http.get(`categories/{id}/attributes`, { params: {sel: ‘many|only’} })

使用的代码:

async getParams (type) {
  const id = this.categoryValues[2]
  const {data: {data, meta}} = await this.$http.get(`categories/${id}/attributes`, {
    params: {sel: type}
  })
  if (meta.status !== 200) return this.$message.error('获取参数数据失败')
  this[type + 'Attrs'] = data
}

校验成功后使用:

// 获取第二个和第三个选项卡的数据
this.getParams('many')
this.getParams('only')

html渲染

<el-tab-pane label="商品参数">
  <el-form label-width="200px">
    <el-form-item v-if="item.attr_vals" v-for="(item,i) in manyAttrs" :key="i" :label="item.attr_name">
      <el-tag v-for="(tag,i) in item.attr_vals.split(',')" :key="i">{{tag}}</el-tag>
    </el-form-item>
  </el-form>
</el-tab-pane>
<el-tab-pane label="商品属性">
  <el-form label-width="200px">
    <el-form-item v-if="item.attr_vals" v-for="(item,i) in onlyAttrs" :key="i" :label="item.attr_name">
      <el-tag style="width: 300px">{{item.attr_vals}}</el-tag>
    </el-form-item>
  </el-form>
</el-tab-pane>

06-商品添加-完成图片上传

使用组件:

<el-upload
  :on-success="handleSuccess"
  :action="action"
  :headers="headers"
  list-type="picture-card"
  :on-preview="handlePictureCardPreview"
  :on-remove="handleRemove">
  <i class="el-icon-plus"></i>
</el-upload>

action 是当前的上传地址 且 全路径

headers 请求的时候 不是通过axios 所以你需要添加token

// 上传图片
dialogImageUrl: '',
dialogVisible: false,
action: this.$http.defaults.baseURL + '/upload/',
headers: {
  Authorization: sessionStorage.getItem('token')
}

// 上传成功后需要给  form.pics 数组追加图片
handleSuccess (res) {
  // 图片地址?  在上传成功后获取响应数据   才有图片地址
  this.form.pics.push({pic: res.data.tmp_path})
},
handleRemove (file, fileList) {
  // 删除图片后台触发的事件
  console.log(file, fileList)
  // 移除 form.pics 中对应的图片对象
  // 根据索引删除一条即可
  // 在file中可以获取当前删除图片的临时路径
  // 根据路径去 form.pics 获取对应的索引
  const tmpPath = file.response.data.tmp_path
  const index = this.form.pics.findIndex(item => item.pic === tmpPath)
  this.form.pics.splice(index, 1)
},
handlePictureCardPreview (file) {
  // 预览图片
  this.dialogImageUrl = file.url
  this.dialogVisible = true
},

07-商品添加-使用富文本插件

  • vue-quill-editor 安装

  • npm i vue-quill-editor

    import VueQuillEditor from 'vue-quill-editor'

    // require styles import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css'

    Vue.use(VueQuillEditor, /* { default global options } */)

组件:

<quill-editor v-model="form.goods_introduce"></quill-editor>

08-商品添加-商品的录入

  • 准备数据
    • 数据在 form 中 attrs 的数据没有准备
    • 其他数据都可以
  • 提交即可
  • 成功:去列表页展示

09-订单列表-组件基础布局

10-订单列表-列表渲染

  • 几乎copy
  • 搜索的时候 接口有问题 请忽略

11-订单列表-收货地址对话框

  • 实现省市区联动
    • 准备 city.js 模块 包含数据
    • 组件 导入 city 模块
    • options 赋值

12-订单列表-物流查询对话框

<!--时间线-->
<el-timeline>
  <el-timeline-item
    v-for="(item, i) in wlList"
    :key="i"
    :timestamp="item.time">
    {{item.context}}
  </el-timeline-item>
</el-timeline>

数据:

wlList: [
  {
    'time': '2018-05-10 09:39:00',
    'ftime': '2018-05-10 09:39:00',
    'context': '已签收,感谢使用顺丰,期待再次为您服务',
    'location': ''
  },
  {
    'time': '2018-05-10 08:23:00',
    'ftime': '2018-05-10 08:23:00',
    'context': '[北京市]北京海淀育新小区营业点派件员 顺丰速运 95338正在为您派件',
    'location': ''
  },
  {
    'time': '2018-05-10 07:32:00',
    'ftime': '2018-05-10 07:32:00',
    'context': '快件到达 [北京海淀育新小区营业点]',
    'location': ''
  },
  {
    'time': '2018-05-10 02:03:00',
    'ftime': '2018-05-10 02:03:00',
    'context': '快件在[北京顺义集散中心]已装车,准备发往 [北京海淀育新小区营业点]',
    'location': ''
  },
  {
    'time': '2018-05-09 23:05:00',
    'ftime': '2018-05-09 23:05:00',
    'context': '快件到达 [北京顺义集散中心]',
    'location': ''
  },
  {
    'time': '2018-05-09 21:21:00',
    'ftime': '2018-05-09 21:21:00',
    'context': '快件在[北京宝胜营业点]已装车,准备发往 [北京顺义集散中心]',
    'location': ''
  },
  {
    'time': '2018-05-09 13:07:00',
    'ftime': '2018-05-09 13:07:00',
    'context': '顺丰速运 已收取快件',
    'location': ''
  },
  {
    'time': '2018-05-09 12:25:03',
    'ftime': '2018-05-09 12:25:03',
    'context': '卖家发货',
    'location': ''
  },
  {
    'time': '2018-05-09 12:22:24',
    'ftime': '2018-05-09 12:22:24',
    'context': '您的订单将由HLA(北京海淀区清河中街店)门店安排发货。',
    'location': ''
  },
  {
    'time': '2018-05-08 21:36:04',
    'ftime': '2018-05-08 21:36:04',
    'context': '商品已经下单',
    'location': ''
  }
]

13-数据报表-echarts使用

/* 1. 引入 echarts 插件 */
/* 2. 准备一个容器 */
/* 3. 实例化echarts对象 需要容器dom */
/* 4. 需要符合echarts规则的配置项 */
/* 5. 设置配置项给实例 */

async getData () {
  const {data: {data, meta}} = await this.$http.get('reports/type/1')
  if (meta.status !== 200) return this.$message.error('获取报表数据失败')
  // 后台给的配置项  和 现在的options 进行合并 然后给图表使用
  const myEcharts = echarts.init(this.$refs.box)
  // Object.assign(o1,o2)  注意:如果有相同key 后面的生效
  const options = {...this.options, ...data}
  myEcharts.setOption(options)
}

14-项目打包

  • 把项目开发是需要依赖的资源合并
  • npm run build
  • 是让webpack进行打包
  • 在 dist 目录
    • 发现:
      • app.xxx.css 较大 (用自己的css 第三方的css)
      • vendor.xxx.js 较大 第三方的依赖
      • app.xxx.js 自己写的js代码 组件代码

15-项目打包优化-路由懒加载

  • 按需加载组件
  • 路由懒加载 按照现在当前的路由去加载需要的组件
    • const Foo = () => import('./Foo.vue')
      

      const Login = () => import('@/components/Login') const Home = () => import('@/components/home/Home') const Welcome = () => import('@/components/home/Welcome') const Users = () => import('@/components/users/Users') const Rights = () => import('@/components/auth/Rights') const Roles = () => import('@/components/auth/Roles') const Categories = () => import('@/components/goods/Categories') const Params = () => import('@/components/goods/Params') const Goods = () => import('@/components/goods/Goods') const GoodsAdd = () => import('@/components/goods/Goods-Add') const Orders = () => import('@/components/orders/Orders') const Reports = () => import('@/components/reports/Reports')

16-项目打包优化-cdn配置

  • 把第三方的资源 使用 外链的方式来加载
  • cdn 服务 提供前端的资源 通过地址就可以访问
    • 第一步 找到 cnd 地址
    • 第二步 在index页面的最底部
    • 第三步 告诉webpack 那些模块不需要打包
      • 是靠配置文件
      • 加配置项 排除打包模块的配置
      • // 使用cdn的js包
          externals: {
            // key (包的名称)  value (js文件暴露在全局的对象名称)
            // 注意 导包后的 接受包的变量和 暴露在全局的对象名称 一致
            'vue': 'Vue',
            'element-ui': 'ELEMENT',
            'echarts': 'echarts'
          },
         module:{}
        

VUE扩展

17-组件传值-父向子

  • 在子组件的自定义标签上写 动态属性 :data='数据'
  • 在子组件中定义 props 的选项 [‘data’]

18-组件传值-子向父

  • 自定义事件 概念
    • 绑定事件 <child-a :say="msg" @toParent="fn">
    • 触发事件 this.$emit('toParent', this.msg)
  • 步骤
    • 你需要在 子组件的自定义标签上绑定一个自定义事件。
    • 如果需要传值给父组件 让子组件去触发这个事件 触发的同时是可以传参的。

19-组件传值-非父子关系

  • 事件总结

    • 统一控制事件的绑定和触发
    • 这是一个模块 暴露vue实例的模块
  • 在A组件 导入 事件总线模块 得到一个实例

    • 用这实例 绑定 一个自定义事件
  • 在B组件 导入 事件总线模块 得到一个实例

    • 用这个实例 触发你在 A 绑定的自定义事件
  • 然后通过事件的回调函数可以传参

    // 事件总线 // 1. 依赖一个VUE实例 import Vue from 'vue' const vm = new Vue() export default vm // 2. 在两个组件中导入这个实例 // 3. 绑定事件 // 4. 在实例中绑定的事件 只有当前实例可以去触发

20-vuex基础-介绍

当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏。

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

  • Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。
  • 这需要对短期和长期效益进行权衡。
  • 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。
  • 确实是如此——如果您的应用够简单,您最好不要使用 Vuex。

总结:项目复杂使用vuex可以简化逻辑,但是如果项目简单使用vuex则会增加逻辑。

结论:

  • Actions 发送请求 响应成功 把数据提交给 Mutations
  • Mutations 接收到数据后 去更新State中的数据
  • State管理的数据是响应式的 当数据改变时渲染视图