精华内容
下载资源
问答
  • 今天分享一个vue项目中在不同列表拖拽设置选项的功能,这个功能也是在做项目中遇到的,先说下这个功能的要点(参考下图),有2个列表,左侧列表展示已选,右侧列表展示未选,通过拖拽进行设置,已选的选项能超过4个...

    今天分享一个vue项目中在不同列表拖拽设置选项的功能,这个功能也是在做项目中遇到的,先说下这个功能的要点(参考下图),有2个列表,左侧列表展示已选,右侧列表展示未选,通过拖拽进行设置,已选的选项不能超过4个,超过的话自动将拖拽之前的最后一项清除到右侧,且如果从已选往未选里拖的时候,右侧显示垃圾桶的提示(如图)。

    拖拽功能图片:

    垃圾桶显示图:

    首先讲讲vue-draggable的使用

    安装vue-draggable:

    npm install vuedraggable

    在使用插件的组件内引入vue-draggable并注册组件:

    1

    2

    3

    4

    5

    import draggable from "vuedraggable"

     

    components: {

     draggable

    }

    然后在我们需要拖拽的列表中使用:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    <draggable class="selected-list" tag="ul"

    v-model="selectedTheme"

    v-bind="dragOptions"

     :move="onMove"

     @end="onEnd"

     >

     <li class="selected-theme"

     v-for="item in selectedTheme"

     :key="item.type"

     >{{item.name}}</li>

    </draggable>

    下面是拖拽功能组件的完整代码:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    111

    112

    113

    114

    115

    116

    117

    118

    119

    120

    121

    122

    123

    124

    125

    126

    127

    128

    129

    130

    131

    132

    133

    134

    135

    136

    137

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    169

    170

    171

    172

    173

    174

    175

    176

    177

    178

    179

    180

    181

    182

    183

    184

    185

    186

    187

    188

    189

    190

    191

    192

    193

    194

    195

    196

    197

    198

    199

    200

    201

    202

    203

    204

    205

    206

    207

    208

    209

    210

    211

    212

    213

    214

    215

    216

    217

    218

    219

    220

    221

    222

    223

    224

    225

    226

    227

    228

    229

    230

    231

    232

    233

    234

    235

    236

    237

    238

    239

    240

    241

    242

    243

    244

    245

    246

    247

    248

    249

    250

    251

    252

    253

    254

    255

    256

    257

    258

    259

    260

    261

    262

    263

    264

    265

    266

    267

    268

    269

    270

    271

    272

    273

    274

    275

    276

    277

    278

    279

    280

    281

    282

    283

    284

    285

    286

    287

    288

    289

    290

    291

    292

    293

    294

    295

    296

    297

    298

    299

    300

    301

    302

    303

    304

    305

    306

    307

    308

    309

    310

    311

    <template>

     <div class="theme-setting">

     <el-dialog

     title="设置选项"

     :visible.sync="dialogVisible"

     width="648px"

     :close-on-click-modal="false"

     >

     <div class="theme-left">

      <dl class="theme-title">

      <dt class="title">当前选项</dt>

      <dd class="des">从右侧拖拽添加</dd>

      </dl>

      <draggable class="selected-list" tag="ul"

      v-model="selectedTheme"

      v-bind="dragOptions"

      :move="onMove"

      @end="onEnd"

      >

      <li class="selected-theme"

      v-for="item in selectedTheme"

      :key="item.type"

      >{{item.name}}</li>

      </draggable>

     </div>

     <div class="theme-right">

      <h3 class="theme-right-title">全部选项</h3>

      <draggable class="theme-right-list" tag="ul"

      v-model="unSelectTheme"

      v-bind="dragOptions"

      :move="onMove"

      @end="onEnd">

      <li class="theme-right-item"

      v-for="item in unSelectTheme"

      :key="item.type"

      >{{item.name}}</li>

      </draggable>

     </div>

     <div class="drag-drop-del" v-show="isShowDel">

      <img src="../assets/imgs/drapDrop/drag_drop_del.png" alt="">

     </div>

     <span slot="footer" class="dialog-footer">

      <el-button @click="restoreDefault">恢复默认设置</el-button>

      <el-button type="primary" @click="saveThemeSet">保存</el-button>

     </span>

     </el-dialog>

     </div>

    </template>

     

    <script>

    import {Message} from 'element-ui'

    import draggable from "vuedraggable"

     export default {

     name: 'DragDrop',

     components: {

     draggable

     },

     data() {

     return {

      dialogVisible: false,

      selectedTheme: [{

      type: 1,

      name: '选项1'

      }, {

      type: 2,

      name: '选项2'

      }, {

      type: 3,

      name: '选项3'

      }, {

      type: 4,

      name: '选项4'

      }], // 已选主题列表

      unSelectTheme: [{

      type: 5,

      name: '选项5'

      }, {

      type: 6,

      name: '选项6'

      }], // 未选主题列表

      backSelectedTheme: [], // 选主题列表备份

      backUnSelectTheme: [], // 未选主题列表备份用于恢复默认设置

      relatedListLast: {}, // 已选主题列表最后一项

      isShowDel: false

     }

     },

     methods: {

     showDrag() {

      this.dialogVisible = true

     },

     onMove({ relatedContext, draggedContext, to }) {

      const relatedElement = relatedContext.element

      const draggedElement = draggedContext.element

      let dragInEl = to['className']

      if (dragInEl == 'selected-list') {

      this.isShowDel = false

      if (this.selectedTheme.length === 4) {

       // 判断往已选列表拖时,如果已经满足4项,则记录已选列表的最后一项

       // 拖拽结束时将此项清除到未选列表中

       this.relatedListLast = this.selectedTheme[this.selectedTheme.length-1]

      }

      } else {

      this.isShowDel = true // 判断如果是往未选列表里拖的话显示垃圾桶

      }

      return (

      (!relatedElement || !relatedElement.fixed) && !draggedElement.fixed

      )

     },

     onEnd(dragObj) {

      let dragInEl = dragObj.to['className']

      if (dragInEl == 'selected-list') {

      if (this.selectedTheme.length > 4) {

       // 判断已选列表大于4项,将记录的最后一项过滤出来,并push到未选列表数组

       this.selectedTheme = this.selectedTheme.filter(item => {

       return item.type != this.relatedListLast.type

       })

       this.unSelectTheme.push(this.relatedListLast)

      }

      }

      if (dragInEl === 'theme-right-list') {

      // 判断是往未选列表拖时,拖拽结束时将垃圾桶隐藏

      this.isShowDel = false

      }

     },

     // 保存设置

     saveThemeSet() {

      const params = {

      taskTopicList: this.selectedTheme

      }

      if (this.selectedTheme.length !== 4) {

      Message({

       type: 'error',

       message: '需设置4个选项 !'

      })

      return false

      }

      $ajax.save(params).then(data => {

      this.dialogVisible = false

      Message({

       type: 'success',

       message: '保存成功!'

      })

      this.$parent.refresh()

      }).catch(err => {

      console.log(err)

      })

     },

     // 恢复默认设置

     restoreDefault() {

      this.selectedTheme = this.backSelectedTheme

      this.unSelectTheme = this.backUnSelectTheme

     }

     },

     computed: {

     dragOptions() {

      return {

      animation: 0,

      group: "description",

      disabled: false,

      ghostClass: "ghost"

      }

     }

     }

     };

    </script>

    <style lang="less" scoped>

    body, ul, dl, dt, dd, li, h1, h3{

     margin: 0;

     padding: 0;

    }

    ul, ol, li {

     list-style: none;

    }

    .theme-setting {

     /deep/.el-dialog {

     height: 476px;

     border-radius: 6px;

     .el-dialog__header {

      height: 55px;

      line-height: 56px;

      padding: 0;

      border-bottom: 1px solid rgba(13,20,30, 0.1);

      .el-dialog__title {

      height:21px;

      font-size:16px;

      font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;

      font-weight:bold;

      color:rgba(13,20,30,1);

      line-height:21px;

      }

      .el-dialog__headerbtn {

      margin-top: -4px;

      }

     }

     .el-dialog__body {

      position: relative;

      display: flex;

      height: 331px;

      padding: 0;

      border-bottom: 1px solid rgba(13,20,30, 0.1);

      .theme-left {

      width: 218px;

      margin-left: 24px;

      border-right: 1px solid rgba(13,20,30, 0.1);

      .theme-title {

       display: flex;

       margin-top: 24px;

       .title {

       height:19px;

       margin-right: 4px;

       font-size:14px;

       font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;

       font-weight:bold;

       color:rgba(13,20,30,1);

       line-height:19px;

       }

       .des {

       height:16px;

       font-size:12px;

       font-family:MicrosoftYaHei;

       color:rgba(13,20,30,0.6);

       line-height:19px;

       }

      }

      .selected-list {

       height: 240px;

       margin-top: 24px;

       overflow: hidden;

       .selected-theme {

       width:160px;

       height:48px;

       line-height:48px;

       text-align: center;

       margin-bottom: 16px;

       cursor: pointer;

       background:linear-gradient(180deg,rgba(43,46,83,1) 0%,rgba(108,116,150,1) 100%);

       border-radius:6px;

       font-size:14px;

       font-family:MicrosoftYaHei;

       color:rgba(255,255,255,1);

       }

      }

      }

      .theme-right {

      padding: 0 24px;

      .theme-right-title {

       padding-top: 24px;

       height:19px;

       font-size:14px;

       font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;

       font-weight:bold;

       color:rgba(13,20,30,0.4);

       line-height:19px;

      }

      .theme-right-list {

       width: 357px;

       height: 240px;

       overflow: scroll;

       margin-top: 24px;

       .theme-right-item {

       width: 160px;

       height:48px;

       line-height:48px;

       float: left;

       margin-right: 16px;

       margin-bottom: 16px;

       background:rgba(247,248,252,1);

       border-radius:6px;

       font-size:14px;

       font-family:MicrosoftYaHei;

       color:rgba(13,20,30,0.4);

       text-align: center;

       cursor: pointer;

       }

      }

      .theme-right-list::before, .theme-right-list::after {

       content: "";

       display: table;

      }

      .theme-right-list::after {

       clear: both;

      }

      }

      .drag-drop-del {

      position: absolute;

      right: 1px;

      top: 0;

      width: 404px;

      height: 331px;

      display: flex;

      justify-content: center;

      align-items: center;

      background-image: url('../../src/assets/imgs/drapDrop/drag_drop.png');

      img {

       width: 96px;

       height: 96px;

      }

      }

     }

     .el-dialog__footer {

      height: 88px;

      padding: 24px 24px 0;

      .dialog-footer {

      .el-button+.el-button {

       margin-left: 16px;

      }

      }

     }

     }

    }

    </style>

    总结

    到此这篇关于Vue使用vue-draggable 插件在不同列表之间拖拽功能的文章就介绍到这了,更多相关vue vue-draggable 插件 拖拽内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    展开全文
  • 第 3 部分:核心功能开发,进行云笔记项目后端核心功能的开发,以登录注册功能为,将项目后端的基石打牢,为后续的快速开发做准备。在这一部分的学习中,你会对 Java 深入了解,自己动手设计安全易用的服务端架构...

    2013 年的时候,我们班同学们一行 8 个人,拉着行李箱,从学校来到北京,开始了漫长的北漂生活。我们学的是计算机技术与应用专业,找工作的方向就是 DBA、前端开发工程师、Java 开发工程师之类的。最开始的两年,工资不是很高,大家就住在回龙观整租的一套三居室里。慢慢的,收入也高了点,大多数人也有了对象,就各自分开租房了。

    原本以为,随着各自工作的发展,我们之间的联系会变少,没想到,近几年,我们总会相互探讨对方的技术领域。原因无他,随着软件开发形势的发展,单纯的 Java 开发工程师、前端开发工程师已经无法满足岗位需要了,全栈开发的呼声越来越高。

    工作多年之后,我们这些人的收入主要取决于两部分:工资和外快。工资要想涨上去,得有实力拿到更好的 Offer。技术领域的单一,是几个同学一直不敢跳槽的原因。面对一些很好的工作岗位,看着职位要求,简历都不敢投啊。

    举个现实点的例子:你在智联招聘里搜索 Java 开发工程师,薪资范围在 10K 以上的,40% 的企业在岗位要求都会有前端开发经验的要求,类似这样的:

    熟悉 HTML5、XML、JavaScript、Ajax、CSS 等 WEB 前端开发技术;

    这样的:

    了解或掌握 jQuery、Bootstrap、ExtJS 等 Javascript 框架的使用;

    还有这样的:

    熟练使用 jquery,Vue,MiniUi等 开源框架;

    对 Java 工程师的前端开发经验有要求的,除了规模在 100 人以下只招 1 到 2 人的小公司外,还有公司规模在 10000 人以上招聘人数 10 人以上的大公司、国营企业。

    对于 Java 开发工程师来说,熟悉 HTML5、JavaScript、CSS 等要求并不是问题,比较难的是对于熟练使用框架的要求

    同样的,搜索 前端开发工程师,也能看出同样的问题。对于前端开发工程师来说,熟悉后端开发语言更是一种考验。更不要说现在软件测试工程师的岗位要求里也开始出现熟悉前后端开发流程至少熟悉一种前后端开发语言的字眼了。

    工资不好涨,那接私活、赚外快呢?打开几个常用的接私活网站,做网站、开发系统、开发 APP 是最常见的工作,也是最有可能做的任务。如果你有合适的搭档,一个人做前端、一个人做后端,确实可以接到点项目、赚些外快。但如果你是纯前端开发或纯后端开发,又没有合适的搭档,这点外快也就很难赚到了。

    拓展自己的技术能力,对于求职、晋升,乃至创业来说都至关重要。而成为一位全栈工程师,将为你带来更好的发展机会。

    本专栏为有志于成为全栈工程师的你量身打造,带你进行一次 Spring Boot + MyBatis + Vue + Element 全栈项目开发实战。我们选用当下主流的技术,带你从零开始实现一个完整的云笔记应用,实现前端、后端、数据库设计与开发流程。

    专栏的每篇文章都有对应的完整代码在 GitHub 上托管。大家既可以参考项目的代码风格规范自己的书写习惯,也可以从中学习到合适的技术知识和设计思想,还可以基于此项目开发自己的系统和应用。

    • 如果你是没有开发经验的在校大学生,想从事开发工作而又不知道选择哪个方向;通过本专栏的学习,可以使你真正参与到前后端分离开发的项目中去,轻松入门全栈开发,在项目的实际开发过程中选择感兴趣的技术方向,并积累足够的项目经验。

    • 如果你是有工作经验的前端开发工程师,对后端开发感兴趣;通过本专栏的学习,可以使你对 Java 后端开发全流程有深入了解,扩展你的知识领域。

    • 如果你是有工作经验的 Java 开发工程师,希望在技术上进一步提升;通过本专栏的学习,不仅可以使你对 Java 各种技术有重新的认知,获取到各种有助于快速开发的工具和设计结构,还可以使你对前端开发全流程有深入了解,并通过快速搭建前端项目、灵活运用各种 Vue.js 组件及 Element UI 控件来完成你想要的功能和页面布局。

    本专栏是我作为 Java 全栈开发工程师多年工作的总结和思考,融合了前后端开发过程中的一系列方法论,严格按照完整的规范化项目开发流程进行,共分为 7 个部分,33 篇。

    • 第 1 部分:项目简介,介绍专栏内容结构,完成项目需求分析,正式立项。在需求分析中,明确项目目标及产品功能树,作为后续项目开发的依据。

    • 第 2 部分:项目前期准备,进行项目正式开发前的所备工作:架构选择、数据库设计、接口文档设计等,以严谨的思想和正式的开发流程对待我们的项目,保证整个项目开发过程有法可依、有据可查。

    • 第 3 部分:核心功能开发,进行云笔记项目后端核心功能的开发,以登录注册功能为引,将项目后端的基石打牢,为后续的快速开发做准备。在这一部分的学习中,你会对 Java 深入了解,自己动手设计安全易用的服务端架构、发送邮件、开发通用工具、存取文件、压缩图像……

    • 第 4 部分:业务功能开发,这一部分重点讲述云笔记项目前端页面的设计,完成云笔记项目的业务功能,带你对 Vue.js 深入了解,掌握 Vue 路由配置、组件化开发、灵活运用各种开源组件。

    • 第 5 部分:后台管理功能开发,这部分介绍云笔记项目的后台管理功能,从功能设计到前后端功能实现,带你完成一个完整的后台管理系统。

    • 第 6 部分:项目升级,这一部分介绍如何将该项目改造能支撑起千万级的用户量大型分布式项目,通过这部分的学习,让你对大数据和高并发产生亲近感:原来你就在这里。

    • 第 7 部分:小结,对本专栏的学习内容总结与回顾,查漏补缺,深入思考,同时也是一个项目完成后对项目进行中的经验与教训的总结。

    通过对本专栏的学习,可以使你具备全栈开发的能力,并拥有以下能力:

    • 项目业务功能的独立分析能力

    • 接口文档、数据库结构的独立设计能力

    • Spring Boot / MyBatis / Vue / Element 等框架的结构与用法

    • Java 反射 / 泛型 / 自定义注解等基础知识

    • Java 发送邮件 / 文件上传 / 图片压缩 / 图片解析等应用场景

    • MyBatis 通用 Mapper / 自动建表等深度使用场景

    • 拖拽组件 vuedraggable / 富文本编辑器 wangeditor / MarkDown 编辑器 mavon-editor / 图表 echarts / Excel 文件保存 file-saver + xlsx 等 Vue.js 组件的使用

    • Http 请求测试工具 Postman  的使用

    • JWT / HTTPS / Nginx 在前后端的应用

    • Redis / RabbitMQ / js-base64 / @vue/cli  / 逆地理编码等其他知识的应用

    从此,找工作不再是岗位挑你,而是你挑岗位;接私活也不再是观望状态,一刀在手,天下我有。所有说,前端开发工程师们、后端开发工程师们,是时候展现真正的技术了。做一名全栈开发工程师,你,准备好了吗?

    即日起至 4 月 10 日,专栏《全栈工程师实战:从 0 开发云笔记》限时特惠!订阅专栏,即刻开启你的全栈工程师之路!

    展开全文
  • 如果这样操作成功的话,去C盘清空一个文件夹: C/用户/administrator/appdata/Roaming/npm-cache 直接将路径下该文件夹右键删除 再重新npm install #删除node_modules npm cache clean --force

    vue2 项目
    ========= vue cmd命令所包含知识点:

    当npm install无效,需要进行npm cache clean --force命令操作,
    如果这样操作不成功的话,去C盘清空一个文件夹:
    C/用户/administrator/appdata/Roaming/npm-cache  直接将路径下该文件夹右键删除
    再重新npm install
    
    #删除node_modules
    npm cache clean --force 强制清楚缓存
    npm install rimraf -g
    rimraf node_modules
    重装:npm install
    
    #canvas库---ocanvas
    npm install ocanvas --save
    import oCanvas from 'ocanvas'
    var oCanvas = require('ocanvas')
    

    路由配置的两种方式

    1. location.hash=“url” 可以通过hash来改变href,但页面不发生刷新
    2. history.pushState({},’’,‘url’) 也可以通过html的history改变路由且不刷新页面
      replaceState() go() back() forward()
    安装vue-router: npm install vue-router --save   
    添加--save是因为项目运行时也需要依赖路由
    
    document.title="首页"    document.title可以改变当前页的网址上的文字描述
    
    学会使用StackOverflow和GitHub提问
    

    在vue3项目中使用scss:

    npm install node-sass --save-dev
    

    全局安装vue3脚手架:

    npm i -g @vue/cli
    

    vue3 通过vite初始化项目: 学习vue3.0,先从搭建环境开始

    yarn/npm create vite-app vue3project
    一步直接创建项目。
    
    vue add  vue-next   让vue支持3.0
    

    =模块化开发====

    1 为什么前端要做模块化开发

    避免多人开发时变量重名等问题

    2 模块化开发的概念

    早期的模块化开发的实现,是通过匿名函数,使得多人开发时变量重名不会影响整体项目。同时将需要全局使用的变量或者函数通过return方式暴露出去–导出。这样就可以在其他位置直接使用–导入。

    3 常见的模块化规范有: AMD, CMD, Modules,CommonJS,

    ===webpack的作用/安装和使用/配置
    1.1webpack安装和使用

    vue脚手架 vue cli=====

    1 脚手架工具的作用:

    帮助完成项目的代码目录结构,项目结构和部署,热加载,代码单元测试等功能。

    vue cli俗称vue项目脚手架,可以快速搭建vue开发环境以及对应的webpack配置。所以使用vue cli需要先安装node(因为webpack的使用需要先安装node,然后才能使用npm—npm为node自带的)

    1. 安装node:
      直接在官网下载安装:http://nodejs.cn/download/

    2. 检测安装的node版本:
      node环境要求版本 >= 8.9

    3. 什么是NPM?node package manager
      npm是一个nodejs包管理和分发工具,已经成为非官方的发布node模块的标准

    国内直接使用npm的官方镜像非常慢,所以推荐使用淘宝npm镜像。
    npm install -g cnpm --registry=https://registry.npm.taobao.org

    一般org网址都是非营利性的。com结尾的网址是营利性的

    安装vue cli3版本,既可以使用3版本,也可以使用2版本。所以直接安装3版本cli就好了。

    npm install -g @vue/cli   安装vue cli3
    cli3版本下创建vue项目:
    vue create projectname
    
    如果按照3版本后想要使用2.x旧版本。可以通过命令直接拉取旧版本
    npm install -g @vue/cli-init
    cli2版本下创建vue项目:
    vue init webpack projectname
    

    runtime compiler / runtion only的区别========
    运行+编译器:可以直接使用template模板.
    仅运行时.无法解析template模板,需要通过render函数提前编译

    ============vue所包含知识点:

    1 input/button具有特别的监听事件

    input有个特有的动态监听事件,用来监听表单数据value的变化。v-on:input/@input
    当input表单内数据value发生变化时会触发:input监听事件

    button也有特有的监听事件

    2 浏览器的event对象

    cli(event) {
      //@click="cli" 当调用方法不传参不加括号时,会自动调用浏览器产生的event对象
      console.log(event);
    },
    cli0(val,event) {
      //@click="cli0(123,$event)" 当需要调用浏览器的event对象又需要传参时。event+$符号
      console.log(val);
      con``sole.log(event);
    },
    

    3 v-model实现数据双向绑定的原理

    v-model实现数据双向绑定的原理: v-model实际上使得vue做了两步操作:
    1.v-bind model—>view
    2,input的特有监听事件@input view—>model

    <input type="text" v-model="message">
    <input type="text" v-bind:value='message' @input="message = $event.target.value">
    

    4 data() { return {} }

    为什么vue在设计的时候data是一个函数,而不是直接一个对象?
    因为对象return的是同一片内存空间。这样会导致组件在复用时,所有复用组件使用同一片内存地址。导致数据紊乱。
    data必须是一个函数。每调用一个组件实例,就会调用一个data函数。而函数return的是一片新的内存地址。这样使得所有复用的组件之间互不影响。

    组件化开发:========

    5 父子组件之间传值

    ++ 4.1 父组件向子组件中传值:

    props:['变量1','变量2','变量3'];//最基础的写法,数组类型,不推荐
    props:{//对象类型,推荐。可以对传过来的值进行类型审核和简单验证,同时也方便阅读和简单维护
        propA:Number,//基础的类型检查
        propB:[String,Number],//多个可能的类型
        propC:{//必填的字符串
            type: String,
            required:true
        },
        propD:{//带默认值的数字类型
            type:Number,
            default:100
        },
        propE:{//带默认值的对象
            type:Object,
            default:function() {//Object or Array的默认值是一个函数
                return { msg:'hi' }
            }
        },
        propF:{//自定义验证函数
            validator:function(value) {
                //这个值必须匹配下列字符串中的一个
                return ['','',''].indexOf(value) !== -1;//返回值true or false 
                //arr.indexOf(item) 判断数组arr中是否包含元素item。如果不包含则返回-1
            }
        }
    }
    

    ++ 4.2 子组件向父组件传值:
    在子组件中使用this.$emit(‘func’,value)
    在父组件调用子组件时:

    <son @func="sonhappen"/>
    methods:{
        sonhappen(value) {
            //注意,父组件中此处接收的值都是string类型。
            console.log(value)
        }
    }
    

    6 父子组件之间的访问

    ++父组件直接访问子组件:
    this. c h i l d r e n : 数 组 类 型 一 般 不 使 用 children: 数组类型 一般不使用 children使children来拿子组件数据。而是使用 r e f s 可 以 访 问 父 组 件 的 所 有 子 组 件 对 象 , 包 括 子 组 件 的 子 组 件 ; 可 以 访 问 子 组 件 的 所 有 数 据 。 t h i s . refs 可以访问父组件的所有子组件对象,包括子组件的子组件;可以访问子组件的所有数据。 this. refs访访this.refs: 对象类型 好像行不通啊??

    this.$refs.name可以访问到son子组件的所有数据。name会作为子组件对象的key值。

    ++子组件访问父组件:
    this. p a r e n t : 可 以 在 子 组 件 中 访 问 到 父 组 件 对 象 。 一 般 开 发 中 不 使 用 。 会 影 响 组 件 的 独 立 性 。 t h i s . parent:可以在子组件中访问到父组件对象。一般开发中不使用。会影响组件的独立性。 this. parent访使this.root:可以在子组件中访问根组件即vue实例对象

    7 v-bind

    v-bind不支持驼峰写法
    v-bind:cInfo=“info” 这样写会出现值传递失败的情况 需要改成v-bind:c-info=“info”

    8 计算属性

    计算属性存在缓存。在多次调用时,由于存在缓存,只会执行一次。
    与methods的区别:methods调用几次执行几次

    9 插槽 slot

    插槽的作用:为了让组件具有可扩展性。

    9.1基本插槽的使用:
    在自定义的组件中使用。可以在插槽内填入默认内容。
    在引用组件时,可以在组件内直接填入内容。就可以替换子组件内插槽的默认内容。

    9.2具名插槽的使用:
    一个子组件内可能存在多个插槽,当引用子组件时,可能只希望替换其中某一个插槽的内容。这时候就可以使用具名插槽。即给每个slot一个特有的name属性值。

    在子组件中:
        <slot name="left"></slot>
        <slot name="center"></slot>
        <slot name="right"></slot>
    在父组件中引用子组件时:
        <son><div slot="center">我要把son组件内的center插槽内容替换掉</div></son>
    

    9.3作用域插槽:
    —有个需求:子组件中包含一个数组数据。需要在不同的位置进行展示。有的地方水平展示,有点地方纵列展示,有的位置直接显示一个数组。希望父组件告知子组件具体如何展示。

    —以上需求就可以使用作用域插槽。展示数据由子组件提供。但展示方式由父组件决定。
    —所以需要先在父组件中拿到子组件的数据:
    1,在子组件中将子组件的数据绑定到abc: [abc可以随意更改成你喜欢的名字]
    在son组件中:



    子组件默认展示


    2,在父组件中引用子组件son时,使用拿到子组件数据: slot.abc就是从子组件获取到的数据




    10 this. r o u t e r t h i s . router this. routerthis.route

    this. r o u t e r 指 的 时 n e w V u e 的 实 例 对 象 t h i s . router 指的时newVue的实例对象 this. routernewVuethis.router.push/this. r o u t e r . r e p l a c e t h i s . router.replace this. router.replacethis.route 指的是当前活跃状态下的路由对象
    { path:’/user/:abc’,component:user } this.$route.params.abc

    11 所有的组件都继承自vue类的原型

    所以通过Vue.prototype.自定义的方法和变量,整个vue项目中的所有组件都可以使用变量或方法

    12 全局导航守卫

    https://blog.csdn.net/qq_36545813/article/details/109510815

    13 router-view是VueRouter的组件。

    13 keep-alive是vue内置的组件,

    可以使被包含的组件保留状态,或避免重新渲染;
    被包裹在keep-alive里面的组件,所有路径匹配到的视图组件都会被缓存。

    keep-alive有两个非常重要的属性,开发者可以自由定义哪些组件需要被缓存,哪些组件需要被重复创建和销毁【一般存在每次进入路由都需要重新更新的情况】
    –inclue属性:只有相匹配的组件才会被缓存–字符串或正则
    –exclue属性:任何相匹配的组件都不会被缓存–字符串或正则
    比如app.vue下有a b c 3个组件,且全部都被keep-alive包裹,但我需要每次切换到组件C时都重新创建。
    可以这样操作: c是组件的name值。如果需要排除多个组件,使用逗号分隔就好,需要注意的是不能多添加空格,否则会出错

    使用vuex

    npm i vuex -S
    npm i es6-promise -S

    使用码云gitee https://blog.csdn.net/qq_36545813/article/details/105673756

    在码云新建仓库并第一次将本地代码提交
    在控制台:
    git comfig --global user.name ‘677’
    git config --global user.email ‘1592713356@qq.com’
    创建本地git仓库:
    mkdir storename
    cd storename
    git init
    touch READEME.md //注意:如果报错touch:无法将’touch’项识别为cmdlet… 安装touch :npm install touch-cli -g 安装后再执行touch READEME.md
    git add READEME.md
    git commit -m ‘first commit’
    git remote add origin https://gitee.com/…
    git push -u origin master

    引用echarts图表

    npm install echarts --save
    在引用echarts的组件内import echarts from ‘echarts’
    绘制一个图表:
    1,准备一个具备宽高的容器:


    2,通过echarts.init初始化一个echarts实例: var myPie = echarts.init(document.getElementById(‘pie’))
    3,通过setOption方法生成图表:
    var option = {}
    myPie.setOption(option)

    #Vuex中执行完mutations,更新了state后,视图不更新 vuex中state数据是异步渲染的。初始渲染的是state中的默认数据。在渲染时去获取三层表达式中的属性值,此时对象还不存在,获取不到值。这样就会造成,在界面上可以正常打印出值,但是
    https://blog.csdn.net/edc3001/article/details/86833558

    vue中实现移动拖拽 h5的drag & drop

    参考:

    @dragstart="Dragstart($event,item)"
    draggable="true"
    *   methods:{
            Dragstart (event, item) {//@dragstart是html自带的mouseevent事件
              console.log('===================dragstart');
              console.log(event);//
              console.log(item);
              var infoJson = JSON.stringify(item.info);
              event.dataTransfer.setData('my-info', infoJson);
            }
        }
    
    • dragstart、drag、dragenter、dragover、dragleave、drop、dragend属性

    • 事件顺序:

    • dragstart -> drag -> dragenter -> dragover -> dragleave -> drop -> dragend

    • 拖放事件

    • (默认图像,链接,文本是可以拖动的)

    • (别的元素要拖动首先设置draggable=“true”:对于draggable的支持ie10+,ie9-只能使用默认拖动)

      1. 被拖放元素拖放事件:
    •  被拖放对象:dragstart:开始拖放的时候触发
      
    •  被拖放对象:drag:在拖放过程中持续触发
      
    •  经过对象:dragenter:拖放过程中鼠标经过的元素,被拖放的元素‘正开始’进入其他元素范围内  e.preventDefault()
      
    •  经过对象:dragover:拖放过程中鼠标经过的元素,被拖放的元素正在本元素范围内移动(一直)   e.preventDefault()
      
    •  经过对象:dragleave:拖放过程中鼠标经过的元素,被拖放的元素离开本元素范围
      
    •  目标地点:drop:拖放元素被放置到目标点的时候触发
      
    •  被拖放对象:dragend:拖放操作结束时触发   
      
      1. 拖放中的数据传递
    •  a.在拖放数据的时候使用dataTransfer来存储和获取数据
      
    •  b.存储数据:ev.dataTransfer.setData("类型","值") 类型通用有两种:"text/plain"和"text/url-list"(ie中使用"text"和"url")
      
    •  c.获取数据:ev.dataTransfer.getData("类型")类型同上
      
    •  (获取数据是在目标对象的drop事件上获取在别的事件上都取不到)
      
    •  (注意设置document的dragover和dragend为return false否则获取不到数据)
      
    •  (目标有几层元素就会触发几次)
      
      1. dropEffect和effectAllowed(这是dataTransfer的两个属性)
    •  对于拖动元素而言在dragstart时设置effectAllowed不为none光标显示为指针而不是禁止标志
      
    •  这两个属性的主要作用:用于设置拖拽过程中鼠标指针的类型。
      
    • 4.dataTransfer属性:

    •  a. clearData(format):清除特定格式的数据
      
    •  b. setDragImg(elem,x,y):设置拖动的时候光标下面显示的图像,(x,y为光标在图像上的位置)
      
    •  (这个方法还是很好用的,但是不支持ie)
      
    • dragenter 和 dragover需要阻止浏览器的默认事件。
      */

    vue兄弟组件之间拖拽失败 尝试安装插件vuedraggable

    http://www.itxst.com/vue-draggable/tutorial.html

    • 因为拖拽组件依赖sortablejs ,如果项目没有安装sortablejs ,可能需要安装一下
    • npm install sortablejs --save
    • npm install vuedraggable --save
    • 局部注册:
      import draggable from ‘vuedraggable’
      components:{
      draggable
      },
    • ====================安装依赖后,dragenter生效 dragend生效 但drop无效
    • 博客参考:https://www.cnblogs.com/birdshome/archive/2006/07/22/Drag_Drop.html#457694
      事件参考:https://developer.mozilla.org/zh-CN/docs/Web/Events 资源事件/键盘事件/鼠标事件/拖放事件/媒体事件/进度事件/触摸事件/浏览器事件等
    • drop事件参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/drop_event
    • https://developer.mozilla.org/zh-CN/docs/Web/API/DragEvent
    • vuedragable插件功能实现拖拽都是操作Array or Object数据:
    • @start
    • @move
    • @changed
    • @end
    • vuedragable插件:https://blog.csdn.net/qq_36545813/article/details/111468646
    • https://blog.csdn.net/zjiang1994/article/details/79809687
    • vue拖拽组件vuedragable-demo:http://www.ptbird.cn/vue-draggable-dragging.html
    • https://sortablejs.github.io/Vue.Draggable/#/clone
    • vue拖拽组件vuedragable-code:https://github.com/SortableJS/Vue.Draggable/blob/master/src
    • vue拖拽插件。使用vuedraggle :思路
      ====开始拖拽时获取到相应组件名。在change时将组件名复制给component 的is属性 还是不可行
      ====通过json文件来定义组件信息,v-for循环组件信息,并通过事件获取当前组件信息。
    • vuedraggable内部元素的click事件与@drop事件冲突问题:
      参考:https://blog.csdn.net/qq_33270001/article/details/106264832

    vue-draggable-resizable: vue3/vue2 可拖拽+调整大小+参考线+对齐吸附 基本所有组态功能这个插件里都有了

    • vue2draggableresizable :https://github.com/gorkys/vue-draggable-resizable-gorkys
    • https://tingtas.com/vue-draggable-resizable-gorkys/?path=/story/%E5%9F%BA%E6%9C%AC–%E7%A6%81%E6%AD%A2%E5%81%9C%E7%94%A8%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%BB%84%E4%BB%B6
    • 博客园文档参考连接:https://www.cnblogs.com/wangweizhang/p/11241788.html
    • 组件事件git连接:https://github.com/gorkys/vue-draggable-resizable-gorkys/blob/master/README_ZH.md
    • demo: https://tingtas.com/vue-draggable-resizable-gorkys/?path=/story/%E5%9F%BA%E6%9C%AC–%E5%9F%BA%E6%9C%AC%E7%BB%84%E4%BB%B6
    • https://blog.csdn.net/ksyjy/article/details/105294894
    • npm install vue-draggable-resizable --save
    • 在main.js引入:全局
      import VueDraggableResizable from ‘vue-draggable-resizable’
      import ‘vue-draggable-resizable/dist/VueDraggableResizable.css’
      Vue.component(‘vue-draggable-resizable’,VueDraggableResizable)
    • 局部引入:
      import VueDraggableResizable from ‘vue-draggable-resizable’
      import ‘vue-draggable-resizable/dist/VueDraggableResizable.css’
    • 常用属性总结:
      https://github.com/gorkys/vue-draggable-resizable-gorkys/blob/master/README_ZH.md#props
    • :lock-aspect-ratio=“true” 保持拖拽组件的宽高比
    • :parent=“true” 限制不能拖出父元素
    • parent=".p-event" 限制不能拖出类名为p-event的元素
    • :active= “true/false” 通过active来自主控制盒子是否为选中状态
    • :prevent-deactivation=“true/false” 通过该属性来定义点击对象外是否需要取消选中状态
    • https://www.npmjs.com/package/vue-draggable-resizable-gorkys
    • 吸附对齐,辅助线,冲突检查等功能需要在插件vue-draggable-resizable-gorkys中才有 ,这个插件是上面插件的升级
      • npm install --save vue-draggable-resizable-gorkys
      • 局部引入:
        import vdr from ‘vue-draggable-resizable-gorkys’
        import ‘vue-draggable-resizable-gorkys/dist/VueDraggableResizable.css’
      • :isConflictCheck=“true” 冲突检查
      • 元素对齐辅助线:
        :debug=“false” 啥意思?
        :snap=“true” 定义组件是否开启元素对齐
        :snapTolerance=“20” 吸附 当调用snap时,定义组件与元素之间的对齐距离,以像素(px)为单位
        @refLineParams=“getRefLineParams”
        :referenceLineColor="#0f0" 辅助线的颜色

    • :grid=[20,20] 盒子内的目标具有偏移
      grid表示水平和垂直轴上移动时,每次能走多少像素
    • :axis=“axis” 表示沿X轴/y轴移动 值:x/y/both
    • @activated=“onActivated” 单击时调用 ,以显示句柄
    • @deactivated=“onDeactivated” 单击组件外的任何位置时调用。
    • :enable-native-drag=“false” 禁用浏览器的本机拖放功能(通常用于图像和其他一些元素),恢复使用true
    • :active.sync=“true” 确定组件是否应处于活动状态
    • :draggable=“false” 定义该组件是否可拖拽
    • :resizable=“false” 默认true
    • class-name-active=“active” 用来定义活跃状态 css: .active{}
      以上属性发现:即使不设置class-name-active=“active”,有css: .active{} 就行

    vue 分割页面布局 用户可自定义拖拽改变:vue-splitpane

    • https://antoniandre.github.io/splitpanes/
    • npm i splitpanes # For Vue 2.x.
    • npm i splitpanes@next # For Vue 3.
    • // In your Vue component.
    • import { Splitpanes, Pane } from ‘splitpanes’
    • import ‘splitpanes/dist/splitpanes.css’
    • export default {
    • components: { Splitpanes, Pane },
    • }

    #批量注册全局方法

    • 定义全局方法 https://www.cnblogs.com/conglvse/p/10062449.html
    • 在main.js引入:import globalmethods from ‘url’ Vue.use(globalmethods)
    • 在所有组件中通过this.function调用

    使用extends继承其他组件 extends可以继承多个吗?

    • 不可以,是单继承。
    • 在canvas绑定拖拽事件:需要在viewcanvas绑定 在组件内部的canvas标签上也要绑定 否则不生效 这样生效的效果是:两个canvas都会同时移动。若要一个canvas对应一个盒子的画。那不能公用一块画布了。
    • 调整了canvas文件结构。使用一个页面用来作画布,再使用一个页面专门用来作画笔–即实现canvas的具体方法。详见代码leftPanel的canvas文件夹。

    自己封装组件。可以通过{{ keydata }}和props:{keydata:{}},在引用封装组件时直接通过这种书写方式来使用:

    使用bootstrapvue https://bootstrap-vue.org/docs

    • npm install bootstrap-vue bootstrap
    • 在mani.js文件中:
    • import Vue from ‘vue’
    • import { BootstrapVue, IconsPlugin } from ‘bootstrap-vue’
    • // Install BootstrapVue
    • Vue.use(BootstrapVue)
    • // Optionally install the BootstrapVue icon components plugin
    • Vue.use(IconsPlugin)
    • import ‘bootstrap/dist/css/bootstrap.css’
    • import ‘bootstrap-vue/dist/bootstrap-vue.css’

    vue封装js文件

    https://www.cnblogs.com/yanl55555/p/12543993.html

    Math

    • Math.floor(Math.random() * (max-min + 1) + min) 生成区间在[min,max]之间的随机数

    对侧边栏实现拖拽的内容进行组件封装

    如何让子组件宽度撑满父容器

    vue: Initialize failed: invalid dom 之 dom加载出现的问题

    • 问题解决的参加博客:https://blog.csdn.net/smalCat/article/details/89091966?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control
    • promise了解: https://blog.csdn.net/qq_36545813/article/details/110121219
    • 导致问题的原因:异步加载。当echarts.init()去初始化的时候,此时DOM还没加载,echarts没有检测到DOM。所以此问题的解决方向让DOM加载后再去init()。可以通过promise异步,读写分离。
    • 我认为还可以使用 this. n e x t T i c k ( ( ) = > ) 表 示 当 D O M 加 载 完 成 时 再 去 执 行 。 但 使 用 p r o m i s e 和 nextTick(() => { }) 表示当DOM加载完成时再去执行。但使用promise和 nextTick(()=>)DOM使promisenextTick后依然报错。=====所以一下没有新的解题思路了。?????? 在画canvas的时候也遇到document.getElementById为null的问题,原因也是DOM未加载就去引用。解决方式使用this.$nextTick()是成功的。
      所以这里的echarts初始化应该是其他问题。待研究。

    键盘事件: https://www.cnblogs.com/eAndyLau/p/12916891.html

    • delete:
      • created () {
      •   document.onkeydown = (e) => {
        
      •       let key = window.event.keyCode;
        
      •       if(key == 46|| key == 8) {//  delete||backspace
        
      •           alert('删除canvas')
        
      •           let id = this.selectedid;
        
      •           console.log(id);
        
      •           const targetcanvas = document.getElementById(id);
        
      •           targetcanvas.remove();//删除元素
        
      •       }
        
      •   }
        
      • }
    • CV事件:
      • (e.keyCode == 67 && e.ctrlKey) ctrl+c
      • if(e.keyCode==86 && e.ctrlKey){
      • alert(“按下了Ctrl+V 键”)
      • }
    • CS / CZ /CN
      e.keyCode == 83 && e.ctrlKey -> Ctrl + S
      e.keyCode == 90 && e.ctrlKey -> Ctrl + Z
      e.keyCOde == 79 && e.ctrlKey -> Ctrl + N

    怎么实现,拖拽进来多少个canvas对象,centertest就生成相应多个canvas呢?而不是像目前一样使用一个canvas标签,通过拖拽的目标对象给canvas的id动态赋值:

    • 想到一个解决方法:centertest默认data为空,每拖拽进来一个对象,就相应push一条数据进去。根据数据,去动态渲染页面。动态控制html标签。
    • 动态push数据,可以使用vuedragable组件自带的事件。===push成功了,但左侧的图标却会消失[原因是:dragable的list属性值和icon渲染的数据为同一条数据,当拖拽后remove一条数据,渲染icon的组件的数据也会减少。处理方法:定义一个空数组,将icon数据全部赋值给它,然后操作这个数组数据,就不会互相影响了]。
    • 使用拖拽插件动态push数据不太可行,push数据的内容是插件自带的封装好的数据,自定义的话反而式代码和逻辑都变得更加麻烦。只要在centertest.vue中,将每一个拖拽过来的当前mes数据进行组合就好了啊!真笨呢在这折腾了大半天
    • 动态push数据后,可以遍历数据生成多个canvas,然后给每个canvas绑定拖拽事件。键盘删除事件,单击双击事件。[根据动态数据渲染生成多个canvas时,每个canvas对应一个唯一ID,那么每个icon图标只能拖拽画一次canvas,否则无效,按说应该会报错,结果页面会生成ID同名的多个canvas,但不会再生成图像。这个问题怎么解决呢?==========虽然每个图标对应一个id,可每拖拽一次,可以给传进来的数据的id值添加索引号。这样就能保证id具有唯一性。再通过getElementId(ID)获取el画布。]
    • [生成的canvas盒子宽高即需要画的图的宽高。而图像的x,y坐标是相对当前画布canvas,新的canvas的坐标应该是画布相对于main盒子的定位?这个问题需要解决。解决完了,再绑定事件。]====但是坐标的相对定位元素是canvas的绘图方法规定的。根据这一点,应该让所有的图都画在一个canvas内。这样才能实现正确的定位。或者,在drop的时候,给canvas定位到相应位置。但自己手写js实现定位,需要用到position,会使得页面发生重绘回流,非常笨重。使用拖拽事件来控制canvas坐标呢?
    • 也可以通过@mousedown获取到当前目标对象的数据信息,显示在右侧侧边栏。然后可以进行样式修改,修改后即时更新数据信息。实现右侧侧边栏可以控制每个目标的样式信息。
    • 进行此操作前可能代码需要一些大的调整,先git保存一份代码。

    对象转数组 ES6 Object.func()用法:

    • https://www.cnblogs.com/ll15888/p/11993334.html。
    • Object.values(obj),Object.keys(obj),Object.entries(obj),for in循环。
    • Object.assign() 合并对象:
      举例: const data = Object.assign({},jsonIcons) //深拷贝jsonIcons数据
      this.icondata.push(data)

    数组转对象:

    判断字符串中是否包含某个子串

    • https://www.cnblogs.com/zhangliang88/p/10644398.html
    • str.indexOf(“3”) != -1 ; // true 不等于-1表示包含

    截取字符串中某个特定字符之前的子字符串/之后的子字符串

    str_before = string.split(str)[0]
    str_after = string.split(str)[1]
    

    获取字符串末尾的一个字符

    string.charAt(string.length-1)
    

    判断两个字符串是否相等 ?

    • https://www.jb51.net/article/154827.htm
    • “==”判断的是两个字符串的值是否相等:
      比如:“123” == 123 一个是字符串,一个是整型,结果为true
      ==只判断值是否相等,当数据类型不相等时,会进行自动类型转换。
    • “===”恒等操作符,数据类型和值都会进行比较。
      比如:“123”=123 第一步先比较类型,直接false
      “123”
      =“123” true

    深拷贝浅拷贝: https://www.jianshu.com/p/1c142ec2ca45

    • 浅拷贝:拷贝的是指针地址,通过指针地址去查找对象,指向同一个内存地址。如果修改对象数据,另一个指向该指针地址的数据也会发生改变。
    • 深拷贝:修改拷贝的数据不会影响原数据。深拷贝针对较为复杂的object类型数据。
    • 实现深拷贝:
      • 通过JSON对象实现深拷贝:[无法实现对对象中方法的深拷贝,会显示undefined]
        • JSON.parse(JSON.stringify({}))
          let str = JSON.stringify(obj) 将对象转字符串
          let ojbclone = JSON.parse(str) 将字符串转对象
        • Object.assign({},jsonIcons) 无效深拷贝

    设置除数后保留两位小数:

    x = y = (boxstyle.circleR / 2).toFixed(2);//除以2保留2位小数
    

    获取鼠标在main面板的坐标: clienxX,offsetLeft… http://c.biancheng.net/view/5960.html

    https://www.jb51.net/article/55128.htm

    const el = document.getElementById(‘main’);//拿到mian盒子的左上角坐标。
    this.x = e.clientX - el.offsetLeft;
    this.y = e.clientY - el.offsetTop;//这就是生成的canvas盒于main盒子的坐标啦!

    CSS 子元素铺满整个父元素/让子元素的宽高随着父元素的宽高缩放:

    通过js给DOM元素添加一个类名:

    • DOM.setAttribute(“class”,“类名”) 该方法会覆盖原有的类名
    • DOM.classList.add(‘类名’) 不会覆盖原有类名 只是添加。

    ant_design_vue的下载和使用:

    • 思否文章:https://segmentfault.com/a/1190000037556136
    • 官网地址https://www.antdv.com/docs/vue/introduce-cn/

    computed监听Vuex中state对象中的对象属性时,监听不生效的问题 mutations

    • https://blog.csdn.net/aliven1/article/details/100581529

    清空canvas画布!!

    • canvas.setAttribute(‘height’,0) 重置canvas的宽高,https://blog.csdn.net/Rainbow1995/article/details/94649695

    怎么清除画布中的某个图像

    • el.getContext(‘2d’).clearRect(x, y, 50, 50)//从坐标x,y开始,擦除一块长宽未50的矩形面积

    删除元素节点:

    • DOM.remove()

    项目中实现,选中一个对象,改变侧边栏数据,让选中对象的样式发生变化的思路:

    1,当侧边栏数据发生变化并提交表单时,传递表单数据。
    2,在center页面监听数据的变化。并给监听属性添加deep:true。保证数据对象内的任意属性值发生变化都会触发事件监听。监听事件触发的条件有两点:对象被选中【可以在点击选中对象时获取对象id。监听时判断是否有id】;侧边栏数据更新后发生了提交【在提交事件中记录标记sub:true】。
    3,

    • 以上操作会出现的bug。当选中对象,提交修改过一次数据后,再次更新侧边栏,不需要提交就会直接触发监听。因为watch具有缓存功能,并且数据对象内任意属性值发生变化都会触发监听,所以有了缓存之后,不需要提交也会触发监听。
    • 解决方法:在右侧边栏监听表单数据。当表单数据任意属性值发生变化时,传递表单数据并记录一个标记sub:false。当center页面触发监听后,判断sub是否为ture。为false则说明本次触发未经过提交事件,为无效触发。

    watch,监听对象内的属性值的变化: https://www.cnblogs.com/my466879168/p/12430648.html

    • watch:{
    • item:{
      
    •     handler:function(newval) {
      
    •         console.log(newval);
      
    •     },
      
    •     deep:true//修改item对象内的任何一个属性,都会触发item的监听。
      
    • }
      
    • }

    获取鼠标距离事件源左上角的坐标

    1,获取鼠标坐标。page/client
    2,获取事件源的左上角坐标。//offsetLeft
    3,相减就是鼠标距离事件源左上角的坐标。

    通过id获取元素宽高:

    document.getElementById(’’).clientWidth/clientHeight

    js遍历键值对数组:

    [0,{},1:{}] => [{},{}] ?
    Object.assign({},data)
    Object.values() 获取对象键值对中的value组成数组 Object.keys()
    arr.push()
    let i in arr

    删除数组中的元素

    获取到id,document.getElementById为null。

    classList:

    • DOM元素对象,该属性用于在元素中添加,移除和切换类。
    • classList.add() classList.remove()

    判断字符串中是否包含数字

    hadNumber(str) {//判断字符串中是否包含数字
        for(let i in str) {
            let asc = str.charCodeAt(i);
            if(asc >= 48 && asc <= 57) {//表示包含数字
                return true;
            }
        }
        return false;//不包含数字
    },
    

    删除字符串中的数字:

    delNumber(str) {//删除字符串中数字返回新字符串
        for(let i in str) {
            let asc = str.charCodeAt(i);
            if(asc >= 48 && asc <= 57) {//表示包含数字
                let needdel = str.charAt(i);//获取索引处的字符
                console.log(needdel);
                str = str.replace(needdel,'');
            }
        }
        console.log(str);
        return str;
    },
    

    arr.map() 遍历数组,不改变原始数组数据

    const newdata = arr.map((element,index) => { //map遍历数组对每个元素进行处理,返回新元素组成的数组。
         // console.log(element);
         element.canvasid += ''+index;
         return element;
     });
    

    点击目标div以外区域将目标div隐藏:

    https://www.cnblogs.com/mica/p/11276447.html

    判断dom1是否包含在dom2元素内

    document.getElementById(id).contains(e.target)

    背景纹理填充:?

    判断obj {} 对象中是否包含某个属性

    https://blog.csdn.net/u012746918/article/details/106359881/

    • obj.hasOwnProperty(‘x’) 返回布尔值
      比如:
      let obj = {x,y}
      var bool = obj.hasOwnProperty(‘x’);//bool->true
    • obj.x != undefined obj存在属性x则返回true 。不存在则返回false
      [该方法存在一个弊端,如果属性的值为undefined,不能返回想要的结果]
    • if(‘x’ in obj) 相当于if(true/false)

    拖拽组态开发功能原理分析:

    https://juejin.cn/post/6908502083075325959
    项目搭建和功能完成都差不多了我才看到这个文档。非常有用,可作为文档参考加深印象或者优化项目。

    js判断obj对象是否为空 {}

    Object.keys(lbj).length==0 为空

    vue 自定义路径别名 @

    • 创建vue.config.js,和package.json同层级
    • const path = require(‘path’)
      const resolve = dir => path.join(__dirname, dir)
      module.exports = {
      baseUrl: ‘./’,
      runtimeCompiler: true,
      chainWebpack: config => {
      config.resolve.alias
      .set(’@’, resolve(‘src’))
      }
      }
    • 重启项目

    动画绑定。

    动画库 Animate.css https://animate.style/ ?
    -1,插件: 本项目中使用animate.css插件

    • npm install animate.css --save
    • import animated from ‘animate.css’
      Vue.use(animated)
    • An animated element

    -2,vue自带的动画效果: transition

    • component is用来动态切换组件,通过mode属性可以设置切换时动画。将id为comName的组件放到对应位置
    • transition 是vue用来提供动画效果的组件。

    -3,css实现动画效果:

    • @keyframes js控制动画效果。document.styleSheets insertRule()
    • css自定义属性/css变量。通过js改变css自定义属性值 https://www.cnblogs.com/hzz-/p/ 11464767.html
      1 const vh = document.documentElement.clientHeight;
      2 document.documentElement.style.setProperty(’–view-height’, vh+‘px’);
      transform translate @keyframes
      //怎么实现动态画矩形? js改变css自定义属性
      //animation: gif 5s infinite;
      // document.getElementById(this.hiddendata.id).style.setProperty(’–view-width’, instanceX);
      // document.getElementById(this.hiddendata.id).style.setProperty(’–view-height’, instanceY);
      // document.getElementById(this.hiddendata.id).style.animation = “gif 5s infinite”;

    动画绑定实现原理:

    1,用一个文件来打包动画需要用到的动画效果数据。
    本项目中使用的是animate.css。可去官网查看动画演示效果,以及获取相关动画属性。
    2,先将所有动画在遮罩层【本项目中使用的标签是抽屉】中渲染出来。先实现悬浮时触发动画。
    只需要使用悬浮事件,改变类名。给任意元素添加移除animatename即可添加或移除动画效果
    @mouseover=“hoverAnimate = animatename”
    :class="[hoverAnimate === animatename?‘animate__’+animatename:’’]"
    3,第三步,点击某个动画效果时,将该动画效果绑定到相应组件。即改变相应组件的class。
    4,动画效果预览。点击相应动画的预览效果时,将相应动画与相关组件绑定。

    事件绑定。原理和动画绑定类似。

    1,用一个文件来存储事件需要的数据
    2,使用遮罩层来进一步控制交互效果。让用户输入事件的参数信息。当用户点击确定按钮时
    3,通过用户的点击事件触发。给相应组件绑定相关的事件监听。
    4,事件预览:在对象选中的情况下,选择单个事件时,对相关对象进行事件监听和事件解绑。

    vue中通过transition使用通过。并在vue中使用Animate.css动画库:

    在这里插入图片描述

    • 1:
      @keyframs name {
      0% {}
      50% {}
      100 % {}
      }
      .fade-enter-active {
      transform-origin: left center;
      animation: name 1s;
      }
      .fade-leave-active {
      transform-origin: left center;
      animation: name 1s reverse;
      }

    • 2:使用Animate.css库和transition结合:

      • npm install animate.css --save
        import animated from ‘animate.css’
        Vue.use(animated)

      • appear:表示第一次显示时有动画效果。
        appear-active-class:用于在组件第一次显示时展示动画效果
        enter-active-class:入场动画 必须有animated
        leave-active-class:出场动画 必须有animated
        duration:自定义动画执行的总时长
        还可以分别定义入场和出场动画的时长:duration="{enter:5000,leave:1000}"
        <transition
        name=""
        :duration=“5000”
        enter-active-class=“animated 自定义添加入场动画”
        leave-active-class=“animated 自定义添加出场动画”
        apear
        appear-active-class=“animated 自定义添加入场动画”
        @berfore-enter=“handleBeforeEnter”
        @enter=“handleEnter”
        @before-leave=""
        @leave=""
        @after-leave=""

        组件

        methods:{
        handleBeforeEnter: el => {
        el.style.color = ‘red’;
        },
        handleEnter: (el,done) => {//el指动画transition包裹的标签
        setTimeout(()=>{
        el.style.color = ‘green’;
        done();//手动结束动画 不可省略 done()被调用后,会执行afterEnter()
        },2000)
        },
        handleAfterEnter: el => {//结束时动画
        el.style.color = ‘black’;
        }
        }

    在vue中使用velocity.js动画库

    文档:http://shouce.jb51.net/velocity/index.html
    下载:npm install velocity-animate

    vue动画封装:

    监听mac下的键盘按键:

    1,使用git工具: 弃用

    • https://github.com/madrobby/keymaster
    • main.js引入
      import keymaster from ‘./utils/keymaster.js’
      Vue.use(keymaster)
    • 组件中使用:keymaster(‘⌘+r’,()=>{})
      2,⭐e.metaKey为布尔值,如果按下的是⌘就返回true。按其他键返回false。等同于e.ctrlKey的true表示键盘按下ctrl键。

    用户自定义控制组件的选中状态 vuedraggableresizable插件的:active属性

    vue mixins和extends的区别:

    https://blog.csdn.net/guoweifeng0012/article/details/87922312

    • mixins可以理解为多继承,extends可以理解为单继承。extends一般用来继承.vue文件,且只能继承一个组件。
    • 结论: 优先调用mixins和extends继承的父类,extends触发的优先级更高
    • push(extend, mixin1, minxin2, 本身的钩子函数)
    • import component_test from ‘…/Func/myFunc’
      data() {},
      watch:{},
      extends:component_test,
      methods:{}
      //component_test组件内的this就是当前extends位置的组件的this。

    事件修饰符:

    .stop 阻止事件冒泡。
    .self 让事件只在本身元素上触发
    使用场景:阻止子元素的点击事件冒泡到父元素。当点击子元素时 ,子元素在父元素内,也相当于点击了父元素。而self确保事件只在子元素上触发

    事件监听

    • https://www.cnblogs.com/fpcbk/p/10112385.html

    addEventListener

    • elementObject.addEventListener(eventName,handle,useCapture)

    事件监听传递参数

    DOM.addEventListener(‘click’,eventHandler.call(this,evt),false);//addEventListener(‘click’,fn,false)

    //eventHandler.call(this,evt) 改变eventHandler函数内的this指向,并传入参数evt

    function eventHandler(evt) {
    console.log(this);
    console.log(evt);
    }

    js判断两个数哪个更大哪个更小 https://www.cnblogs.com/my12-28/p/11815579.html

    Math.min(start.x,end,x)
    Math.max(start.x,end,x)

    js截取字符串’-'前/后的子字符串

    str.split(’-’)[1] 表示截取str字符串-后的子串
    比如button-11 str.split(’-’)[1]表示’11’ str.split(’-’)[0]表示’button’

    实现鼠标全选:

    • 框选范围内的对象。鼠标按下并移动时,动态画矩形。
    • 鼠标弹起时,如果框选范围内有对象,显示矩形,并使区域内所有对象表现为选中状态;
    • 鼠标弹起时,如果框选范围内无对象,矩形宽高值置0,div隐藏。
    • 当点击框选矩形外区域时,矩形宽高置0,div隐藏。表现为选中状态的对象们都取消选中。
    • 当单击框选范围内单个对象时,其他对象取消选中状态,框选矩形置0且隐藏。
    • 当点击框选矩形范围内空白区域并移动时,矩形和矩形区域内所有对象跟随鼠标移动。

    for循环和闭包。闭包函数会在for循环结束后才执行。假如闭包写在循环内,怎样才能实现循环依次执行依次闭包?

    js给同一DOM同时绑定单击和双击事件的解决方案。

    • 参考:https://www.hangge.com/blog/cache/detail_1794.html
    • 理解:原生js单击和双击存在冲突,不能同时触发。双击相当于在简短时间内连续单击。因此同时时间间隔来判断调用单击还是双击。

    使用模板字面量 vvv ,来拼接字符串和对象,还可以引入表达式,也支持换行

    this. m e s s a g e . e r r o r ( “ 该 对 象 已 绑 定 ” + e v t . l a b e l + “ , 请 勿 重 复 绑 定 ” ) ; t h i s . message.error(“该对象已绑定”+evt.label+“,请勿重复绑定”); this. message.error(+evt.label+);this.message.error(该对象已绑定“${evt.label}”,请勿重复绑定);

    event.preventDefault() 通知浏览器不要执行于事件相关联的默认动作

    event.stopPropagation() 阻止事件冒泡

    如何实现echarts宽高自适应 随着盒子的resize而改变大小

    vue this.$refs

    如何在json文件中引用另一个json文件

    js 取绝对值

    Math.abs(-1); //1
    Math.abs(-2); //2

    vue 监听watch:

    • 监听对象的所有属性:
      watch: {
      obj: {
      handler: function() {
      //do something
      },
      deep: true
      }
      }
    • 监听对象的某个属性:
      watch: {
      ‘obj.name’: {
      handler: function() {
      //do something
      },
      }
      }

    echarts图表自适应

    该方法是在页面已经存在图表的情况下。
    let opt=myChart.getOption();
    myChart.clear();
    myChart.resize({height:“500px”,width:“500px”});
    myChart.setOption(opt);

    echarts//避免控制台警告:There is a chart instance already initialized on the dom.

    https://blog.csdn.net/qq_26477073/article/details/84568668
    let myEchart;//全局变量
    if (myEchart != null && myEchart != “” && myEchart != undefined) {
    myEchart.dispose();//销毁
    }

    vue+webpack项目动态设置页面title的方法

    https://blog.csdn.net/weixin_42333548/article/details/103626427

    vue如何将组件内容保存为html页面

    • 1:点击预览时,获取center的innerHTML。
      在预览位置将获取的innerHTML设置为自己本身的innerHTML
      点击保存时,弹出下载窗口,指定将文件保存为html格式。
    • 2:通过 https://blog.csdn.net/sangjinchao/article/details/70888259:
      保存为html跳转和传参。在center页点击跳转到center页。并重新赋值centerdata。让页面重新渲染

    js 如何弹出下载窗口

    如何实现保存html

    vue导出为pdf:

    https://blog.csdn.net/SpringRolls/article/details/108105014
    https://blog.csdn.net/u012732909/article/details/108124313

    • 将html页面转换成图片
      npm install --save html2canvas
      将图片生成pdf
      npm install jspdf --save

    将vue文件分离成html、css、js多个文件

    vue下载文件保存到本地:

    参考链接:https://blog.csdn.net/txp1993/article/details/70046443/
    最推荐这个链接了:看一遍更加深入理解:https://www.cnblogs.com/liuxianan/p/js-download.html

    vue中写全局js文件的写法:

    1,//js文件
    export default{
    install (Vue) {
    //将getPdf定义为全局方法
    Vue.prototype.getPdf = () => {

    }
    

    }
    }

    2,在main.js文件中引入:
    import htmlToPdf from ‘@/utils/htmlToPdf’
    Vue.use(htmlToPdf)

    3,在其他任何位置直接通过函数名调用全局方法

    鼠标右键:

    @contextmenu=“rightclick”
    rightclick() {
    // console.log(‘单击了鼠标右键’);
    },

    translate 和rotate组合使用的问题:https://blog.csdn.net/hellokingqwe/article/details/52602315

    translate平移,rote绕几何中心旋转。旋转后,坐标轴会发生变化。此时translate平移所参考的坐标轴就是新坐标轴了。

    如何解决组合使用问题呢?
    :style="{
    ‘transform’:‘translate(’+item.info.form.box.left+‘px,’+item.info.form.box.top+‘px) rotate(’+item.info.form.box.rotate+‘deg)’
    }"

    判断鼠标是否点击在某个对象或者点击在某个区域内或者区域外?

    let tag = window.event.target || window.event.srcElement;
    tag.tagName.toLowerCase()==‘body’
    document.getElementById(‘dragendarea’).contains(tag) 返回true / false //判断鼠标是否点击在#dragendarea区域内

    改变this指向 fn.call()

    https://www.cnblogs.com/hjson/p/10254555.html

    通过this生成modal对话框 https://www.antdv.com/components/modal-cn/

    https://cn.vuejs.org/v2/guide/render-function.html

    const h = this. c r e a t e E l e m e n t ; / / v u e 的 c r e a t e E l e m e n t 函 数 c o n s t h = t h i s . createElement;//vue的createElement函数 const h = this. createElement;//vuecreateElementconsth=this.createElement;
    const content = h(‘div’,{},[
    h(‘a-input’,{
    attrs:{
    placeholder,
    value:’’,
    id:‘input_url’
    }
    // nativeOn:{//用于监听原生事件
    // pressEnter: onOk()//希望回车能执行onOk
    // }
    })
    ]);
    this.$confirm({
    title: ‘请输入跳转路径’,
    content:content,
    okText: ‘确认’,
    cancelText: ‘取消’,
    onOk() {},
    onCancel() {}
    });

    • 怎么获取到自己创建的input内的数据呢?
      document.getElementById(’?’).value

    • 如果content是input标签,怎么实现input回车时关闭modal呢。即使用回车事件代替onOk()事件。

    js事件穿透

    document.getElementById(item.newid).style = ‘pointer-events:none’;//设置事件穿透;
    setTimeout( ()=> {//半秒钟之后,恢复不穿透状态
    // document.getElementById(item.newid).style = ‘pointer-events:auto’;
    // },500)

    已实现:

    1,拖拽效果,鼠标按下,出现一个半透明对象,跟随鼠标拖动。draggable功能自带。
    2,移动和resize效果。插件vuedraggableresizable。
    3,键盘del键删除选中的单个对象。 DOM事件。和数据处理 arr.splice(index,1)
    4,选中对象,ctrl+c,ctrl+v 。复制粘贴选中对象。并指定粘贴位置。 dom事件。arr.push()
    5,移动对象。改变坐标。
    6,改变选中对象样式。选中时获取对象样式,侧边栏数据也随着对象的切换而变化。侧边栏修改单个样式直接修改对象的样式显示效果。
    7,撤回上一步操作。撤回cv。撤回删除。撤回新增。撤回移动。撤回resize。—?还没有撤回样式修改的功能【比如改变了颜色和border等,撤回】。

    剩余实现:鼠标单击并拖拉,实现范围内选取对象。

    1,选取范围内的对象,并获取到选取的所有对象信息,根据鼠标坐标,分别改变每个选取对象的坐标,实现整体移动的效果。并在选取区域形成一个border。⭐
    2,单击选取范围内的单个对象,可对单个对象进行操作和样式修改。此时再拖拉整个选取区域,范围内对象不再整体移动,而是只移动border ⭐
    3,选取范围内对象后,可以将对象整合成一个组件。?不明白具体实现的是什么。动态生成组件吗?
    4,撤回样式修改。
    5,生成html。
    6,预览。
    7,保存。
    8,编辑。
    9,绑定事件。
    10,绑定动画。
    11,触发mac的键盘监听控制事件。⭐
    12,alert弹窗改为ant-vue弹窗。 ⭐

    =====================================

    vue 3

    vite: vue中用于替代webpack打包工具的工具

    • npm install -g create-vite-app
    • 利用vite创建项目:create-vite-app projectname
    • cd projectname
    • npm install
    • npm run dev

    Composition API和Option API

    • vue3组合API–Composition API–setup()的理解:
      • setup(){}函数是组合API的入口函数。
      • 在组合API中定义的变量/方法,必须通过return {} 才能被外界使用
      • setup()执行时机:
        • setup:在setup中无法使用data和methods。所以在setup中打印this为undefined。无法使用
        • befereCreate:data和methods还没有初始化好;
        • created:组件刚刚被创建,data和methods已经初始化好;
        • [setup函数只能是同步处理。]
      • vue3中,可以通过直接定义function,并return {},在setup函数中引用:let {func} = func() 并return {func}。这样做的好处是逻辑块非常清晰,数据的定义和获取,以及逻辑都可以写在一个function块内。this都不用了。
    • Option API:vue2中的使用方式,比如有data(),有methods:{},watch:{},computed:{},生命周期函数等
    • vue3可以Composition API和Option API混合使用。

    函数监听:写在setup函数内

    • reactive():
    *  [实现响应式数据:通过ES6的proxy实现。将传入的数据包装成一个【Proxy对象】。【vue2中通过defineProperty实现】
    *   监听复杂类型的变化【比如对象/数组】:import {reactive} from 'vue'>  监到数据发生变化,会即时响应到页面
    *   let data = reactive({
            stus:[]
        })
    *   如果给reactive传递了其他对象:
        -  默认情况下修改对象,界面不会响应更新
        -  如果想更新,可以通过重新赋值的方式
        setup() {
            let state = reactive({
                time: new Date()
            });
            function myfun () => {
                const newtime = new Date(state.time.getTime());//创建一个新data对 象,和state.time值一样。
                newtime.setDate(state.time.getDate() + 1);//给newtime的天数重设置 为time的天数+1
                state.time = newtime;//对state.time重新赋值。这样,页面中显示的state.time就能实时响应了。
            }
            return {state,myfun};
        }
    
    • ref(): import {ref} from ‘vue’ 通过ref()可以将数据变成响应式数据
      • 监听简单类型的变化:也可以监听【比如对象/数组】
      • ref本质还是reactive,ref函数底层会自动将ref转成reactive:且在页面上{{age}}会自动添加.value
        ref(18) -> reactive({value:18})
      • 所以如果要修改ref的值:
        let age = ref(18);
        function myfun() {
        //age = 666;这样修改不会在页面响应更新
        age.value = 666;//这样可以响应式修改age
        }
        return {age,myfun};
    • ref与reactive的区别:ref数据在页面上会自动添加.value属性。
    • vue中存在isRef()和isReactive()函数,可以判断数据是否是ref/reactive 返回true/false

    递归监听:每一层都可以监听子节点层对象。

    • 默认情况下,ref和reactive都是递归监听。
    • 弊端:如果数据量庞大,非常消耗性能。

    非递归监听:只能监听第一层

    • shallowReactive,shallowRef
    • 如果使用非递归监听,必须对第一层进行处理,再修改第二层第三层等才会生效。如果不处理第一层,直接修改第二层,是无效操作。
    • 如果只想修改第四层的数据并希望页面响应式更新呢?
      使用triggerRef(state) 不存在triggerReactive()函数,如果是shallowReactive无法主动触发监听。

    toRaw,markRow,toRef,toRefs,reactive,ref,等函数,都是用来进行性能优化的作用

    • toRaw():如果有一些方法不需要实时更新页面,就可以通过toRaw函数拿到原始数据。
      • 获取reactive响应式数据的原始数据: toRaw(state)
      • 获取ref响应式数据的原始数据:toRaw(state.value)
    • markRow(obj): 表示对象obj永远都不需要被追踪,不需要响应式修改。
    • toRef(): 将某个对象中的数据变成响应式的数据。[修改数据会影响原始数据]。且修改数据[不会触发页面更新]。[引 用]。浅拷贝。
      • ref()和toRef()的区别 :
        利用ref将某个对象中的属性变成响应式的数据,[修改响应式数据不会影响原始数据]。[复制]。深拷贝。[数据发生变化,界面会自动更新。]
      • toRef()应用场景:
        如果想让响应式数据和以前的数据关联起来,并且更新数据不想更新页面,就可以使用toRef();
    • toRefs(par1,par2): 只能接收两个参数

    customeRef():通过customeRef允许用户自定义ref:返回一个ref对象,可以显式地控制依赖追踪和触发响应

    • track()告诉vue数据需要追踪变化 trigger()告诉vue触发界面更新

    readonly():用于创建只读数据,无法修改。递归只读,每一层都是只读的。

    • shallowReadonly(),第一层只读
    • isReadonly()
    • readonly与const 的区别:const属于赋值保护,不允许给变量重新赋值,readonly属于属性保护,不能给属性重新赋值。

    vue3中响应式数据的本质:

    • vue3通过proxy实现: get() set() { return true;//set方法最后一步一定要return true,告诉vue操作成功了。 }
    • vue2通过defineProperty实现:

    typescript

    ts定义:

    ts是js的超级,包含了es6和es5的规范,适用于大型项目。浏览器无法识别。使用ts后,需要转es5,会自动转的。
    

    npm install typescript -g tsc hello.ts–>会自动将ts转js

    ts面向对象编程,编程语法有点类似Java欸

    MongoDB

    newnew:

    npm install ant-design-vue --save

    展开全文

空空如也

空空如也

1 2 3
收藏数 42
精华内容 16
关键字:

vuedraggable引不进vue

vue 订阅