2022-09-06日积月累(2)

1.根据对象的某个属性排序

① sort()会改变原数组。
② sort()在不传入参数时默认升序排列。
③ 若想自定义排序,如降序排列,按照对象某个属性排序等,就必须往sort()中传入一个回调函数作为参数。

var arr = [
    {name:'zopp',age:0},
    {name:'gpp',age:18},
    {name:'yjj',age:8}
];

//定义一个比较器
function compare(prop){
    // 默认传入两个参数,即为数组中要比较的两项
    return function(a,b){
        var value1 = a[prop];
        var value2 = b[prop];
        // 通过返回值的正负来排序,返回值必须是数字类型
        return value1 - value2;
    }
}
arr.sort(compare('age'))
console.log(arr)
2.render函数渲染DOM结构

示例:
https://blog.csdn.net/qq_36711388/article/details/88980908

在vue-easytable组件中,调用renderBodyCell函数,自定义表格内容。生成两个span标签:

renderBodyCell: ({ row, column, rowIndex }, h) => {
            return h(
              'span', [h('span', {
                domProps: {
                  innerHTML: '编辑'
                },
                style: {
                  color: 'blue',
                  marginRight: '4px',
                  cursor: 'pointer'
                },
                on: {
                  click: () => {
                    this.$message('编辑')
                  }
                }
              }), h('span', {
                domProps: {
                  innerHTML: '作废'
                },
                style: {
                  color: 'blue',
                  cursor: 'pointer'
                },
                on: {
                  click: () => {
                    this.$message('作废')
                  }
                }
              })]
            );
          },
3. 富文本编辑器

(1)vue2.0
https://www.cnblogs.com/wjlbk/p/12884661.html

(2)vue3.0 quill富文本编辑器
vue-admin-plus: https://chu1204505056.gitee.io/admin-plus/#/vab/richTextEditor
Quill文档:https://www.kancloud.cn/liuwave/quill/1409423
注意:获取富文本编辑器实例时,要用 var quill = this.$refs.quillRef2.editor.__quill

  // 41.富文本上传图片成功
      quillSucess(res) {
        var quill = this.$refs.quillRef1.editor.__quill
        let length = quill.getSelection(true).index
        // 插入图片
        quill.insertEmbed(length, 'image', res.data.pic_cover)
        // 调整光标到最后
        quill.setSelection(length + 1)
      },

(3)tinymce富文本编辑器
参考来源:tinymce

仅在工具栏添加自定义按钮:
先在工具栏配置项中添加 按钮名,然后在 init 函数中配置下面的方法。

setup: (editor) => {
  editor.ui.registry.addButton(‘mybutton’, {
     // 按钮名
     text: '图片',
     // icon: false,
     //点击事件
     onAction: () => {
       console.log('点击')
     }
  })
}

封装的组件:
数据双向绑定问题和光标问题:https://blog.csdn.net/tonywu1992/article/details/82953577

<template>
  <div class="tinymceDiv">
    <textarea :id="id" v-model="content"></textarea>
    <el-button @click="click">测试</el-button>

    <!-- 富文本弹框 -->
    <vab-upload
      ref="vabUpload"
      :limit="1"
      name="picture"
      :size="2"
      url="/upload"
      @quillSucess="quillSucess($event)"
    />
  </div>
</template>
<script>
  import VabUpload from '@/extra/VabUpload'
  import tinymce from 'tinymce/tinymce'
  //这下面是tinymce的插件

  //5.0+版本会页面显示not Found,引入图标可以解决这个问题 2021.11.11添加
  import 'tinymce/icons/default/icons.js' // 引入图标包 icons.js

  import 'tinymce/themes/silver/theme'
  import 'tinymce/plugins/image' // 插入上传图片插件
  import 'tinymce/plugins/media' // 插入视频插件
  import 'tinymce/plugins/table' // 插入表格插件
  import 'tinymce/plugins/lists' // 列表插件
  import 'tinymce/plugins/wordcount' // 字数统计插件
  import 'tinymce/plugins/code' //显示源代码插件
  import 'tinymce/plugins/advlist' // 这几条引入是因为我的导入不了,不知道为啥
  import 'tinymce/plugins/link'
  import 'tinymce/plugins/textcolor'
  import 'tinymce/plugins/paste'
  import 'tinymce/plugins/colorpicker'
  import 'tinymce/plugins/contextmenu'
  import axios from 'axios'
  import { getPicList } from '@/api/goodsGroupList'

  //这里写你自己存放语言包的路径
  import '@/assets/lang/zh_CN.js'
  export default {
    name: '',

    components: { VabUpload },
    props: {
      id: String,
      tinyVal: String, //内容绑定
    },
    data() {
      return {
        flag: true,
        content: '子组件内容',
        uploadHeader: {
          'X-Auth-Token': this.$store.state.user.token,
          'Access-Shop-Id': this.$store.state.user.shopId,
        },
        album_id: '',
        init: {
          selector: '#' + this.id,
          language: 'zh_CN',
          // skin_url: 'tinymce/skins/ui/oxide',
          //插件-实现插入图片等功能
          plugins:
            'link lists image code table colorpicker textcolor wordcount contextmenu',
          //工具栏-根据自己需要增减功能
          toolbar:
            'bold italic underline strikethrough  | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | undo redo | link unlink mybutton code | removeformat',
          branding: false,
          menubar: true, //顶部菜单栏显示
          min_height: 500, //高度
          statusbar: false,
          setup: (editor) => {
            // 1.定义按钮,
            editor.ui.registry.addButton('mybutton', {
              // 按钮名
              text: '图片',
              // icon: false,
              onAction: () => {
                this.$refs['vabUpload'].handleShow()
              },
            })
            // 2.监听富文本的变化
            editor.on('input undo redo execCommand', async () => {
              this.flag = false
              // 获取富文本最新内容
              const content = window.tinymce.activeEditor.getContent()
              await this.$emit('update:tinyVal', content)
            })
          },
        },
      }
    },
    watch: {
      tinyVal: {
        handler: function (val) {
          if (this.flag) {
            tinymce.get(this.id).setContent(val) //动态设置内容
          }
          this.flag = true
        },
      },
    },
    created() {
      this.getPicList()
    },

    mounted() {
      //配置的初始化
      tinymce.init(this.init)
    },

    beforeUnmount() {
      //销毁
      tinymce.get(this.id).destroy()
    },

    methods: {
      click() {
        this.$nextTick(() => {
          console.log(this.content)
        })
      },
      /**外部调用该方法,可以拿到绑定数据*/
      release() {
        //content 是文本内容带标签
        let content = tinymce.get(this.id).getContent()
        // getContent( { 'format' : 'text'} );//这是获取里面的文本文件,不带标签
        return content
      },
      /**外部调用该方法,可以修改绑定数据*/
      setData(data) {
        tinymce.get(this.id).getContent(data)
      }, //数据回填

      // 33.获取相册列表
      async getPicList() {
        const { data } = await getPicList()
        const item = data.data.find((item) => {
          return item.album_name == '默认相册'
        })
        this.album_id = item.album_id
      },

      // 43.富文本上传图片成功
      quillSucess(res) {
        window.tinymce
          .get(this.id)
          .insertContent(`<img src="${res.data.pic_cover}" >`)
        const content = window.tinymce.activeEditor.getContent()
        this.$emit('update:tinyVal', content)
      },
    },
  }
</script>
<style>
  .tinymceDiv {
    width: 100%;
    height: 100%;
  }
</style>

4.$refs找不到元素

dialog弹出框中的元素,用$refs获取不到,即使加了 nextTick()方法也不行。
此时可以在dailog的 open 方法的回调函数中获取。

捕获.PNG

showDialog() {
        this.$nextTick(() => {
          console.log(this.$refs.tableRef)
        })
      },
5.element UI表格嵌套上传组件
              <el-table-column align="center" label="sku图片">
                  <template #default="{ row }">
                    <el-upload
                      ref="specPicRef"
                      action="https://muyang.api.zhidingtong.com/admin/album/picture/upload"
                      :auto-upload="true"
                      :before-upload="beforeUpload"
                      class="specUpload"
                      :data="{ album_id: album_id }"
                      :headers="uploadHeader"
                      list-type="picture-card"
                      name="picture"
                     //重点在于可以通过这种方式拿到表格当前行的数据row,和上传的内容res
                      :on-success="(res) => specPicSuccess(res, row)"
                      :show-file-list="false"
                    >
                      <template #default>
                        <i class="el-icon-plus"></i>
                      </template>
                    </el-upload>
                  </template>
                </el-table-column>
6. sku列表-生成所有排列组合
let arr = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [10, 11, 12],
];
 
function cartesianProductOf() {
    return Array.prototype.reduce.call(arguments,       function(a, b) {
        var ret = [];
        a.forEach(function(a) {
            b.forEach(function(b) {
                ret.push(a.concat([b]));
            });
        });
        return ret;
    }, [[]]);
}
 
let allArr =cartesianProductOf(...arr )
console.log(allArr) // 得到的结果就是所有的排列组合组成的数组
7. 编辑页面离开时销毁对应标签
this.$store.dispatch('tabs/delVisitedRoute', 'marketing/updatediscount')
捕获.PNG
8. 本地服务启动

1.打开phpStudy,启动mysql
2.打开Navicat Premium,创建数据库,运行sql文件生成表。
3.在sql文件所在目录,打开cmd,运行npm start启动本地服务。

9.参数传递

在用v-for渲染数据时,给循环单项绑定事件时,用 $$event 传递 事件对象形参,用$index传递当前索引形参

10.在使用element-ui的无限滚动组件时,必须给滚动的盒子高度(宽度)。
11.页面刷新时computed中内部依赖的data数据为underfine

https://blog.csdn.net/weixin_49696014/article/details/112316036

12. 颜色选择器样式

elementUI的下拉选择器、颜色选择器等组件的 下拉框 ,不是直接插入到vue组件的html结构中的。
对于颜色选择器,可以添加 popper-class 属性,并将css样式写到 "App.vue"页面中。

13.拖拽
14.nextTick(()=>{}) 也无法获取到最新DOM元素时,可以尝试在内部加上setTimeout()定时器。
      nextTick(() => {
        setTimeout(() => {
          xxxxxxx
        }, 0);
      });
15.循环渲染的input表单,在输入时总是自动失焦,可能跟key值有关。
16. :deep() ,v-deep,::deep
17. vue.cli的webpack反向代理

(1)为什么存在跨域?
当下,最流行的就是前后分离项目,也就是前端项目和后端接口并不在一个域名之下,那么前端项目访问后端接口必然存在跨域的行为。

(2)跨域分几种情况?
跨域分为 开发环境的跨域生产环境的跨域。前端人员在本地开发,与后端接口存在跨域;上线后,项目在腾讯、百度的服务器上,与后端接口也存在跨域。

(3)如何解决开发环境的跨域?
开发环境的跨域,也就是在vue-cli脚手架环境下开发启动服务时,我们访问接口所遇到的跨域问题,vue-cli为我们在本地开启了一个服务,可以通过这个服务帮我们代理请求,解决跨域问题。(本机请求远程服务器时会因为跨域问题请求失败,改为本机请求webpack启动的本地后端服务,再由本地后端服务请求远程服务器)

(4)具体配置。

module.exports = {
  devServer: {
   // 代理配置
    proxy: {
        // 1.代码中所有包含"/api"的接口都会被匹配到
        '/api': {
        target: "http://192.168.4.164:8080", // 2.远程服务器地址
        changeOrigin: true, // 3.是否跨域 需要设置此值为true 才可以让本地服务代理我们发出请求
        pathRewrite: {
            '^/api': '' // 4.固定写法,如果真正请求的服务器接口url中不包含"/api",此配置可以去除url中的"/api"。
        }
      },
    }
  }
}

① 在vue.config.js配置文件中,添加反向代理的配置内容----> proxy对象。

② api:代码中的所有接口都应该包含"/api",包含"/api"的接口才会被匹配到。

③ target:真正的服务器接口url,需包含协议、域名、端口号。

④ changeOrigin:是否跨域。值为true时,才能让本地服务的后端代替我们发出请求。

⑤ pathRewrite:固定写法。如果真正的服务器接口url中不包含"/api",此配置可以去除url中的"/api"。

⑥ 代码中的接口都以 "/api" 开头,再把axios中的 baseUrl属性 设置为空字符串;
或者代码中的接口只包含此接口的特有部分,然后将axios的 baseUrl属性 设置为 "/api",这样可以为所有接口加上统一的前缀 "/api"。如下:

const service = axios.create({
  baseURL:"/api", // 1.为所有接口添加api前缀
  timeout: 10000
})
export function getDeviceInfo(params) {
  return request({
    url: '/myExample', // 2.接口url中不需要再以/api开头
    method: 'get',
    params
  })
}

⑦ 如上接口,代码中的接口url是 "/api/myExample",我们会请求本地服务 "http://localhost/api/myExample",本地服务会代理到真实的服务器"http://192.168.4.164:8080/myExample"

注意:修改配置后需重启项目才生效。
https://segmentfault.com/a/1190000043775780

  1. 组件库中,组件的 属性、事件、方法。v-bind 、v-on 、this.$refs
18. 项目引入已配置好的mock。

1.创建自己的项目,重点在于填写baseurl。
http://172.18.255.8:9999/
2.代码中,在vue.config.js中,反向代理处,添加mock的反向代理配置。

proxy: {
      '/mock': {
        target: 'http://172.18.255.8:38880/mock',
        changeOrigin: true,
        rewrite: (paths) => paths.replace(/^\/mock/, ''),
      },
    },

3.每个接口,传参时传入mock参数,如果mock为true,则在接口地址"/api"前面加上"/mock"。这样,代理就会走mock的反向代理。
4.mock的一些api:http://mockjs.com/examples.html#String

19.select框不显示placehoder提示内容

绑定的value值设置为undefined即可。

20.contains方法

用于判断Dom元素father是否包含Dom元素child,返回 布尔值

const father= document.querySelector('.father');
const child= document.querySelector('.child');
const flag = father.contains(child)

应用:点击toolTip框之外的部分,隐藏toolTip框;点击toolTip框本身则保持为显示状态。

// 页面文档添加点击事件的监听
document.addEventListener('click', (e) => {
  const toolTipDom = document.querySelector('.toolTip');// 获取toolTip框Dom元素
  if(toolTipDomDom && !toolTipDom.contains(e.target)){
    //关闭toolTip框
  }
});
21. router.push()方法更新当前页面路由,无法实现页面更新

问题:
1.进入详情页时,地址上带了query参数。
2.处理完当前页的内容后,想要通过router.push()更新当前页的query参数。
3.发现页面路由地址虽然更新了,页面数据不更新。
解决:
1.先从详情页router.replace()到一个空页面。
2.在空页面中再次router.replace()到详情页即可。
3.router.replace()方法,不会再浏览器中留下记录,即不能后退到空白页。

22.svg 图标
<svg class="icon" aria-hidden="true">
   <use xlink:href="#icon-fuzhi" />
</svg>
23.不想让滚动条挤到元素
overflow-y: overlay;
24.下载代码中的文件

1.在public目录下新建static文件夹,把文件放到里面

  // 下载模板
  const downloadTemplate = () => {
    const a = document.createElement('a');
    a.href = '/static/批量绑定邮箱模板.xlsx';
    a.download = '批量绑定邮箱模板.xlsx';
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click();
    a.remove();
  };
25.样式混入

如果要定义一个公共样式,其他元素都能复用:scss语法可以用@mixin + @include方式;less语法可以用.aaa(){} 方法定义公共样式,用.bbb{.aaa()}进行调用。

26.对象、函数和类
  • 对象中,一般都是要使用 键值对 的形式,但也可以 省略function 关键字,直接写入一个函数。
  • 中间用 冒号 连接,结尾用 逗号 分隔。
    (1)vue2.0中的 export default{} 一个配置对象。
export default {
  data(){}, // 常见写法
  data: function() {}, // 也可以这样
}
  • 函数体内<script></script>标签内,要使用const、let、function来声明变量与方法(普通函数用function声明,匿名函数用const声明常量接收)。
  • 中间用 等号 连接,结尾用 分号 分隔。
    function a(){};
    const b = ()=>{};
  • class类中 不能使用const、let关键字。
  • 中间用 等号 连接结尾用 分号 分隔。
    class A {
      a(){}; // 常见写法:该方法被放到类的原型对象上
      b = function(){}; // 函数表达式形式:该方法被直接被放到类上,而不是类的原型对象上。
      c = 1;  // 类中可以直接写 赋值语句,就是往类的 实例对象 上直接追加一个属性。
    }
27.axios请求头headers

Content-Type值为application/x-www-form-urlencoded;charset=UTF-8时,参数需要用JSON.stringify()或qs.stringify()转为JSON格式。Content-Type值为 application/json 时,参数不要再做处理。

28.Content-Type

1.文件上传时,接口报错500,但是用ponstman可以上传成功。
2.普通接口报错415,提示Metia Type Error。
解决方案:新建一个axios实例对象,不设置Content-Type

// 文件导入时,不设置默认的Content-Type
export let fileHttp = axios.create({
  baseURL: baseUrl,
  timeout: 10000,
  withCredentials: true,
})
fileHttp.interceptors.request.use(()=>{},()=>{})
fileHttp.interceptors.response.use(()=>{},()=>{})
29.post上传raw格式的参数
// request是axios的实例对象
export function saveNetworkSetting(data) {
  return request.post('/network/save', data, {
    headers: {
      'Content-Type': 'application/json'
    }
  })
   saveInfo(type) {
      const params = {...this.form};
      const arr = [params]; // raw参数一般是个数组
      saveNetworkSetting(arr).then(res => {
        
      })
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容