vue新版本解析,代号”one-piece“

# 其他组件

clipboard-polyfill xgplayer qrcode

# vue-i18n-next

https://github.com/intlify/vue-i18n-next

Vue i18n解决方案

# 拖动组件

vue-draggable-resizable-gorkys

vue-draggable-resizable

# vue-echarts

安装

npm install echarts vue-echarts
1

在vue2中使用还需要安装compostion包

npm i -D @vue/composition-api
1

如果在NuxtJS中使用还需要安装另外一个包

npm i -D @nuxtjs/composition-api
1

并且在nuxt.config.js中添加配置

@nuxtjs/composition-api/module
1

在vue3中使用

import { createApp } from 'vue'
import ECharts from 'vue-echarts'
import { use } from "echarts/core"

// import ECharts modules manually to reduce bundle size
import {
  CanvasRenderer
} from 'echarts/renderers'
import {
  BarChart
} from 'echarts/charts'
import {
  GridComponent,
  TooltipComponent
} from 'echarts/components'

use([
  CanvasRenderer,
  BarChart,
  GridComponent,
  TooltipComponent
])

const app = createApp(...)

// register globally (or you can do it locally)
app.component('v-chart', ECharts)

app.mount(...)
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

在vue2中使用

import Vue from 'vue'
import ECharts from 'vue-echarts'
import { use } from 'echarts/core'

// import ECharts modules manually to reduce bundle size
import {
  CanvasRenderer
} from 'echarts/renderers'
import {
  BarChart
} from 'echarts/charts'
import {
  GridComponent,
  TooltipComponent
} from 'echarts/components'

use([
  CanvasRenderer,
  BarChart,
  GridComponent,
  TooltipComponent
]);

// register globally (or you can do it locally)
Vue.component('v-chart', ECharts)

new Vue(...)
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

# 轮播图

安装包

npm install vue-awesome-swiper --save
1

引入

//全局引入
import VueAwesomeSwiper from 'vue-awesome-swiper'

import 'swiper/dist/css/swiper.css'
Vue.use(VueAwesomeSwiper)
//组件引入
import 'swiper/dist/css/swiper.css'

import {Swiper,swiperSlide} from 'vue-awesome-swiper'
1
2
3
4
5
6
7
8
9

修改swiper属性,自动播放与延时


1

# vue-starport

提供页面与页面/组件与组件之间切换的动画

安装

npm i vue-starport
1

使用

<script setup>
import { StarportCarrier } from 'vue-starport'
</script>

<template>
  <StarportCarrier> <!-- here -->
    <RouterView />
  </StarportCarrier>
</template>
1
2
3
4
5
6
7
8
9

# volar

https://github.com/johnsoncodehk/volar

# 验证码

https://www.npmjs.com/package/vue2-verify

# 多级菜单

递归组件实现

子组件,MenuItem 是一个 li 标签和 slot 插槽,允许往里头加入各种元素

// Menuitem
<template>
  <li class="item">
    <slot />
  </li>
</template>
1
2
3
4
5
6

父组件Menu,Menu中有两种情况需要做判断,一种是 item 没有 children 属性,直接在 MenuItem 的插槽加入一个 span 元素渲染 item 的 title 即可;另一种是包含了 children 属性的 item 这种情况下,不仅需要渲染 title 还需要再次引入 Menu 做递归操作,将 item.children 作为路由传入到 router prop

<!-- Menu -->

<template>
  <ul class="wrapper">
    <!-- 遍历 router 菜单数据 -->
    <menuitem :key="index" v-for="(item, index) in router">
      <!-- 对于没有 children 子菜单的 item -->
      <span class="item-title" v-if="!item.children">{{item.name}}</span>

      <!-- 对于有 children 子菜单的 item -->
      <template v-else>
        <span @click="handleToggleShow">{{item.name}}</span>
        <!-- 递归操作 -->
        <menu :router="item.children" v-if="toggleShow"></menu>
      </template>
    </menuitem>
  </ul>
</template>

<script>
  import MenuItem from "./MenuItem";

  export default {
    name: "Menu",
    props: ["router"], // Menu 组件接受一个 router 作为菜单数据
    components: { MenuItem },
    data() {
      return {
        toggleShow: false // toggle 状态
      };
    },
    methods: {
      handleToggleShow() {
        // 处理 toggle 状态的是否展开子菜单 handler
        this.toggleShow = !this.toggleShow;
      }
    }
  };
</script>
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

路由数据

[
  {
    name: "About",
    path: "/about",
    children: [
      {
        name: "About US",
        path: "/about/us"
      },
      {
        name: "About Comp",
        path: "/about/company",
        children: [
          {
            name: "About Comp A",
            path: "/about/company/A",
            children: [
              {
                name: "About Comp A 1",
                path: "/about/company/A/1"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    name: "Link",
    path: "/link"
  }
];
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

# markdown编辑器

mavon-editor

npm install mavon-editor --save
1

在app.js引入

import mavonEditor from 'mavon-editor'
Vue.use(mavonEditor)
1
2

在页面引入

<template>
<div>
    <mavon-editor v-model='content'/>
    </div>
</template>
<script>
export default{
    data(){
        return{
            content:'',
        }
    },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 直播

播放器使用的是 vue-video-player (opens new window),其实就是 video.js (opens new window) 集成到 vue 中,后台主要输出 RTMP 和 HLS 的直播流

  1. 如果需要播放 HLS 流,需要安装 videojs-contrib-hls (opens new window) 插件,非原生支持的浏览器,直播服务端需要开启 CORS(后面会讲到)
  2. 如果需要播放 RTMP 流,需要安装 videojs-flash (opens new window) 插件
  3. 如果两个流都需要播放,flash 插件需要安装到 hls 插件之前

兼容性:

  1. RTMP: 上面说了 RTMP 是 Adobe 公司研发的协议,目前主要的直播服务都主推 RTMP 流,它延时小,但是需要 flash 插件的支持,也需要的上面提到的安装 videojs-flash 的插件。但是在 MAC 下对 flash 插件支持不友好,而且 MAC 下的 flash 插件 firefox 浏览器和 chrome 还是两个插件。。这就很尴尬。
  2. HLS: 这个协议兼容性较好,但是最大的缺点是延迟较高,大概 20s 左右,所以只能当做备选方案。

说 HLS 兼容性较好,主要是指可以通过 JS 让用户免配置(不必安装flash),可以在 caniuse 看下 HLS 的支持程度

最后我们使用的方案是。优先使用 RTMP 流,如果不支持,就切换到 HLS 流。好在这个切换过程 video.js 会自动替我们做。下面贴一下相关配置代码。

https://segmentfault.com/a/1190000011346597

# 循环播放插件

Vue-seamless-scroll

安装

npm install vue-seamless-scroll --save
1

在文件中引入

import vueSeamlessScroll from 'vue-seamless-scroll'

export default {
  data(){
    return {
     components:{
       vueSeamlessScroll
     }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11

在页面中使用

<template>
  <vue-seamless-scroll :data="Array" :class-option="classOption">
     	<ul>
      	<li>
          
				</li>
  		</ul>
  </vue-seamless-scroll>
</template>
<script>
export default {
  computed:{
    classOption () {
      return {
        //上下滚动时父容器指定height和overflow:hidden,左右滚动时指定width
        step:0.2 //数值越大,滚动速度越快
        limitMoveNum: 2 //开始无缝滚动的数据量
        hoverStop: true //是否开启鼠标悬停stop
        direction: 0 //0向下,1向上,2向左,3向右
      }
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# vue-auth

安装包

npm install @websnaova/vue-auth
1

# vue-pdf

# 输出导入excel文件

使用sheetjs库

安装

npm install xlsx
1

# 输出打印

vue-print-nb

安装

npm install --save vue-print-nb
1

在main.js中全局引入

import Print from 'vue-print-nb'

Vue.use(Print)
1
2
3

通过id打印

<tr id="printInfo">
  
</tr>
<el-button 
   type = "primary"
   key = "printInfo"
   v-print = "'#printInfo'">
</el-button>
1
2
3
4
5
6
7
8

要打印的组件必须渲染出来,否则会报错。

# 地图

leafletjs

leaflet是一个对移动端优化的交互地图并且开源的JavaScript库,是一个十分轻量级的WebGIS库。

安装

npm install leaflet --save
1

引入

vue-amap

安装包

npm install -S vue-amap // 可在package.json查看是否安装
1

在入口文件main.js引入

    // 引入高德地图
    // 高德地图组件使用
    import VueAMap from 'vue-amap'
    
    Vue.config.productionTip = false
    Vue.use(VueAMap);
    VueAMap.initAMapApiLoader({
      key: 'your amap key', 
      plugin: [
      'AMap.Autocomplete', 
      'AMap.PlaceSearch', // POI搜索插件
      'AMap.Scale', // 右下角缩略图插件 比例尺
      'AMap.OverView', 
      'AMap.ToolBar', // 地图工具条
      'AMap.MapType', 
      'AMap.PolyEditor', 
      'AMap.CircleEditor',// 圆形编辑器插件
      'AMap.Geolocation'// 定位控件,用来获取和展示用户主机所在的经纬度位置
      ],
      // 默认高德 sdk 版本为 1.4.4
      v: '1.4.4'
    });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

实例

<div class="getlocation">
  定位
</div>
<el-amap vid="amap" :plugin="plugin" class="amap-demo" :center="center">		</el-amap>
<div class="toolbar">
  <span v-if="loaded">location: lng = {{ lng }} lat = {{ lat }}</span>
	<span v-else>正在定位</span>
</div>
<script>
  export default {
    data() {
      let self = this;
      return {
        center: [121.59996, 31.197646],
        lng: 0, 
        lat: 0,
        loaded: false,
        plugin: [
          {
            pName: "Geolocation", //定位
            events: {
              init(o) {
                // o 是高德地图定位插件实例
                o.getCurrentPosition((status, result) => {
                  if (result && result.position) {
                    console.log(status, result);
                    self.lng = result.position.lng; //设置经度
                    self.lat = result.position.lat; //设置维度
                    self.center = [self.lng, self.lat]; //设置中心坐标
                    self.loaded = true;
                    self.$nextTick();
                  }
                });
              }
            }
          }
        ]
      };
    },
</script>    
<style>
  .getlocation{
    margin-left:4rem;
    font-size:15px;
    font-weight: 500;
    margin-top:0.3rem;
  }
  .amap-demo {
    height: 15rem;
    margin-top: 0.3rem;
  }
</style>
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

百度地图

安装

npm i --save vue-baidu-map
1

初始化

import Vue from 'vue'
import BaiduMap from 'vue-baidu-map'

Vue.use(BaiduMap, {
  /* Visit http://lbsyun.baidu.com/apiconsole/key for details about app key. */
  ak: 'YOUR_APP_KEY'
})
1
2
3
4
5
6
7
<template>
  <baidu-map class="map">
  </baidu-map>
</template>

<style>
/* The container of BaiduMap must be set width & height. */
.map {
  width: 100%;
  height: 300px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12

# 导航

使用ip定位,需要在head标签里面引入js

<script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>
1

在vue中使用

<script>
  mounted () {
    this.loadBaiduMapAsync()
  },
  methods: {
    /**
     * 初始化百度地图并定位用户当前位置
     */
    loadBaiduMapAsync() {
      // 加载百度地图js
      let script = document.createElement('script')
      script.src = 'https://api.map.baidu.com/api?v=2.0&ak=申请的key&callback=initMap'
      document.body.appendChild(script)
      script.onload = (data) => { // 地图js加载成功
        console.log('百度地图JS加载成功,开始定位')
        window.initMap = this.startLocate
      }
      script.onerror = (data) => { // 地图js加载失败
        console.log('百度地图JS加载失败,无法定位')
        common.showConfirm('温馨提示','地图加载出错,请重试!', () => { this.loadBaiduMapAsync() }, null, '重新加载')
      }
    },
    /**
     * 获取用户当前定位 -- APP端端
     */
    startLocate() {
      if (this.isApp) { // APP端
          this.getPositionByAPP().then(point => {
            console.log('APP定位成功--位置:', point);
            this.currPos = point
            this.showMapAndGuide() // 展示地图及导航
          }).catch(msg => {
            this.status = 0
            console.log(msg);
            // common.showToast(msg, CONSTANTS.ERR_TOAST_TIME)
            this.showDestination() // 展示地图和目的地
          })
      } else { // 浏览器端
        this.getPositionByH5().then(point => {
          console.log('浏览器定位成功--位置:', point);
          this.currPos = point
          this.showMapAndGuide() // 展示地图及导航
        }).catch(msg => {
          this.status = 0
          console.log(msg);
          // common.showToast(msg, CONSTANTS.ERR_TOAST_TIME)
          this.showDestination() // 展示地图和目的地
        })
      }
    },
    /**
     * 获取用户当前定位 -- APP端端
     */
    getPositionByAPP() {
      return new Promise(function(resolve, reject) {
        const cb = (err, data) => {
          if (err) {
            if (err.code === '001') { // 未开启定位服务
              reject('请检查您的定位服务是否开启')
            } else if (err.code === '002') { // 未授权应用访问定位功能
              reject('请授权APP访问您的位置信息')
            } else {
              console.warn(err);
              reject('定位失败,位置信息不可用')
            }
          } else { // app定位成功
            let point = {
              longitude: data.Longitude,
              latitude: data.Latitude
            }
            if (this.isiOS) { // IOS坐标转换
              console.log('IOS坐标转换')
              const convertor = new BMap.Convertor()
              convertor.translate([new BMap.Point(point.longitude, point.latitude)], 1, 5, res => { // 经纬度转换,否则会定位不准
                if (res.status === 0) {
                  point.latitude = res.points[0].lat
                  point.longitude = res.points[0].lng
                  resolve(point)
                }
              })
            } else { // Andorid坐标
              resolve(point)
            }
          }
        }
        app.getCurrentLocation(cb)
      })
    },
    /**
     * 获取用户当前定位 -- 浏览器端
     */
    getPositionByH5() {
      return new Promise(function(resolve, reject) {
        const locateByIP = function () {
          if (window.returnCitySN && window.returnCitySN.cip) { // 根据IP,通过百度api获得经纬度
            console.log('returnCitySN:', window.returnCitySN);
            $.getJSON("https://api.map.baidu.com/location/ip?callback=?", {
              'ak' : '申请的百度地图key',
              'coor' : 'bd09ll', // 百度经纬度坐标
              'ip' : window.returnCitySN.cip // {cip: "116.77.145.35", cid: "440300", cname: "广东省深圳市"}
            }, function(data) {
              if (data && data.content) {
                resolve({
                  longitude: data.content.point.x,
                  latitude: data.content.point.y
                })
              } else {
                reject('定位失败,位置信息不可用')
              }
            })
          }
        }

        if (navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(function(pos) {
            resolve({
              longitude: pos.coords.longitude,
              latitude: pos.coords.latitude
            })
          }, function(error) {
            let msg = ''
            switch(error.code) {
                case error.PERMISSION_DENIED:
                    msg="用户拒绝对获取地理位置的请求。"
                    break;
                case error.POSITION_UNAVAILABLE:
                    msg="位置信息是不可用的。"
                    break;
                case error.TIMEOUT:
                    msg="请求用户地理位置超时。"
                    break;
                case error.UNKNOWN_ERROR:
                    msg="未知错误。"
                    break;
            }
            reject(msg)
            // console.warn('浏览器端(geolocation定位失败)-根据IP定位');
            // locateByIP()
          }, {
            enableHighAccuracy: true, // 指示浏览器获取高精度的位置,默认为false
            timeout: 5000, // 指定获取地理位置的超时时间,默认不限时,单位为毫秒
            maximumAge: 2000 // 最长有效期,在重复获取地理位置时,此参数指定多久再次获取位置。
          })
        } else {
          reject('定位失败,当前浏览器不支持定位!')
          // console.warn('浏览器端(geolocation定位不支持)-根据IP定位');
          // locateByIP()
        }
      })

    },
    /**
     * 展示目标位置
     */
    showDestination() {
      if (Number.isNaN(this.lng)|| Number.isNaN(this.lat)) {
        common.showAlert('地址参数错误!', CONSTANTS.ERR_TOAST_TIME)
        return
      }
      // 展示地图
      const map = new BMap.Map("allmap")
      const endPos = new BMap.Point(this.urlParams.lng, this.urlParams.lat)
      // 展示目标位置
      this.status = 2
      map.centerAndZoom(endPos, 16)
      map.addOverlay(new BMap.Marker(endPos))
      map.enableScrollWheelZoom(true)
      // 在右上角添加缩放控件
      const zoom = new BMap.NavigationControl({
        anchor: BMAP_ANCHOR_TOP_RIGHT,
        type: BMAP_NAVIGATION_CONTROL_LARGE,
        enableGeolocation: true
      })
      map.addControl(zoom)
    },
    /**
     * 展示地图并导航
     */
    showMapAndGuide() {
      if (Number.isNaN(this.lng)|| Number.isNaN(this.lat)) {
        common.showAlert('页面地址参数错误!', CONSTANTS.ERR_TOAST_TIME)
        return
      }
      // 展示地图
      const map = new BMap.Map("allmap")
      const startPos = new BMap.Point(this.currPos.longitude, this.currPos.latitude) // {lng: 114.02597366, lat: 22.54605355}
      const endPos = new BMap.Point(this.lng, this.lat)

      // 逆地址解析用户当前所在地址
      const geoc = new BMap.Geocoder()
      geoc.getLocation(startPos, res => {
        const currCity = res.addressComponents.city // 用户当前定位所在城市
        console.log(`定位城市:${currCity} -- 球场地址:${this.address}`);
        if (this.cityName && this.cityName.indexOf(currCity) > -1) { // 用户和目标球场在同一城市
          this.status = 1
          map.centerAndZoom(startPos, 16)
          this.driveRoute(map, startPos, endPos, true)
        } else { // 用户和目标球场不在同一城市
          this.status = 2
          map.centerAndZoom(endPos, 16)
          map.addOverlay(new BMap.Marker(endPos))
          // this.driveRoute(map, startPos, endPos, true)
        }
      })

      map.enableScrollWheelZoom(true)
      // 在右上角添加缩放控件
      const zoom = new BMap.NavigationControl({
        anchor: BMAP_ANCHOR_TOP_RIGHT,
        type: BMAP_NAVIGATION_CONTROL_LARGE,
        enableGeolocation: true
      })
      map.addControl(zoom)
    },
    /**
     * 计算驾驶路线
     * @param startPos BMap.Point 起点位置
     * @param endPos BMap.Point 终点位置
     * @param show Boolean
     */
    driveRoute(map, startPos, endPos, show) {
      const DRIVE = new BMap.DrivingRoute(map, {
        renderOptions: {
          map: map,
          autoViewport: show,
        },
        onSearchComplete: res => {
          let plan = res.getPlan(0)
          console.warn('查询驾车方案结果:', plan);
          if (plan) {
            this.driveDistance = plan.getDistance(true)
            this.driveTime = plan.getDuration(true)
          }
        },
        onMarkersSet: routes => {
          // map.removeOverlay(routes[0].marker)
          // map.removeOverlay(routes[1].marker)
          // 解决百度地图起始点图标重叠问题
          const eles = $('.BMap_Marker img')
          if (eles.length > 0) {
            eles.forEach(v => {
              v.style.maxWidth = 'none'
              v.style.width = '94px'
            })
          }
        }
      })
      DRIVE.search(startPos, endPos)
    }
  }
}
</script>
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

# vue-tour

网站导航包

使用

npm install vue-tour
1

全局导入

import Vue from 'vue'
import App from './App.vue'
import VueTour from 'vue-tour'

require('vue-tour/dist/vue-tour.css')

Vue.use(VueTour)

new Vue({
  render: h => h(App)
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11

使用

<template>
  <div>
    <div id="v-step-0">A DOM element on your page. The first step will pop on this element because its ID is 'v-step-0'.</div>
    <div class="v-step-1">A DOM element on your page. The second step will pop on this element because its ID is 'v-step-1'.</div>
    <div data-v-step="2">A DOM element on your page. The third and final step will pop on this element because its ID is 'v-step-2'.</div>

    <v-tour name="myTour" :steps="steps"></v-tour>
  </div>
</template>

<script>
  export default {
    name: 'my-tour',
    data () {
      return {
        steps: [
          {
            target: '#v-step-0',  // We're using document.querySelector() under the hood
            header: {
              title: 'Get Started',
            },
            content: `Discover <strong>Vue Tour</strong>!`
          },
          {
            target: '.v-step-1',
            content: 'An awesome plugin made with Vue.js!'
          },
          {
            target: '[data-v-step="2"]',
            content: 'Try it, you\'ll love it!<br>You can put HTML in the steps and completely customize the DOM to suit your needs.',
            params: {
              placement: 'top' // Any valid Popper.js placement. See https://popper.js.org/popper-documentation.html#Popper.placements
            }
          }
        ]
      }
    },
    mounted: function () {
      this.$tours['myTour'].start()
    }
  }
</script>
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

# Element-plus

# petite-vue

轻量级的vue

<script type="module">
  import { createApp } from 'https://unpkg.com/petite-vue?module'

  createApp({
    // exposed to all expressions
    count: 0,
    // getters
    get plusOne() {
      return this.count + 1
    },
    // methods
    increment() {
      this.count++
    }
  }).mount()
</script>

<!-- v-scope value can be omitted -->
<div v-scope>
  <p>{{ count }}</p>
  <p>{{ plusOne }}</p>
  <button @click="increment">increment</button>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Last Updated: 2/19/2024, 12:16:30 AM