在这里,我们将给大家分享关于AntDesignVue中TreeSelect详解的知识,让您更了解antdesignvuetree的本质,同时也会涉及到如何更有效地2019Electron+Vue+An
在这里,我们将给大家分享关于Ant Design Vue中TreeSelect详解的知识,让您更了解ant design vue tree的本质,同时也会涉及到如何更有效地2019Electron+Vue+Ant Design Vue仿网易云音乐windows客户端实战分享、Ant Design Mobile Ant Design Mobile Ant Design 移动端设计规范的 React 实现、Ant Design of Vue select框获取key和name的问题、ant design of vue 中的select问题的内容。
本文目录一览:- Ant Design Vue中TreeSelect详解(ant design vue tree)
- 2019Electron+Vue+Ant Design Vue仿网易云音乐windows客户端实战分享
- Ant Design Mobile Ant Design Mobile Ant Design 移动端设计规范的 React 实现
- Ant Design of Vue select框获取key和name的问题
- ant design of vue 中的select问题
Ant Design Vue中TreeSelect详解(ant design vue tree)
<template>
<a-tree-select
v-model:value="value":tree-data="treeData"
allow-clear
@select="selectHnader"
search-placeholder="Please select"
/>
</template>
<script lang="ts">
import { TreeSelect } from 'ant-design-vue';
import { defineComponent,ref,toRefs,watch } from 'vue';
const treeData = [
{
title: '部门0-0',value: '0-0',key: '0-0',children: [
{
title: '部门0-0-0',value: '0-0-0',key: '0-0-0',},],{
title: '部门0-1',value: '0-1',key: '0-1',children: [
{
title: '部门0-1-0',value: '0-1-0',key: '0-1-0',disabled: true,// 该值不能够选中
},{
title: '教育局',value: '0-1-1',key: '0-1-1',]
export default defineComponent({
setup() {
// 那么它将选中部门 部门0-0-0;
// 通过value值显示对应的title值
const value = ref(['0-0-0']);
// 监听,但是可能不需要
watch(value,() => {
console.log(value.value);
});
function selectHnader(value:any,node:any,extray:any){
console.log("==>value",value); //获取的是数据源中的value值
console.log("==>node",toRefs(node) ); // 该选中节点的属性
console.log("==>extray",extray.selectednodes[0].props.title); //得到显示的值
}
return {
value,treeData,selectHnader
};
},});
</script>
使用select事件
select 事件 被选中时调用
function(value,node,extra)
我使用 select事件主要是得到选中的显示值
最初我还想通过递归根据id得到显示的值{哈哈。尴尬了}
2019Electron+Vue+Ant Design Vue仿网易云音乐windows客户端实战分享
特点
- 视频播放器
- 拖拽播放
- 桌面歌词
- mini模式
- 自定义托盘右键菜单
- 任务栏缩略图,歌曲操作
- 音频可视化
- 自动/手动检查更新
- Nedb数据库持久化
- 自定义安装路径,安装界面美化
- 浏览器中启动客户端
- Travis CL,AppVeyor自动构建
- 换肤,下载,本地歌曲匹配,网络变化桌面通知,分享歌曲/歌单/MV/视频等到QQ空间
- 登录,私人Fm,歌单,专辑,歌手,排行榜,MV,视频,评论,搜索,用户,动态,粉丝,关注,云盘,收藏...
- 心动模式,歌词微调,下一首播放,追加播放,单曲循环,随机播放,列表循环
- 路由导向,局部刷新,首页栏目调整并持久化...
- ...
下载 && 运行
项目地址
点击下载应用。
macOS用户请下载dmg文件,windows用户请下载exe文件,linux用户请下载AppImage文件。项目当前依赖NeteaseCloudMusicApi,感谢NeteaseCloudMusicApi的作者。
当前只为windows做了适配 。
基于draggabilly封装一个可拖动的对话框
拖动对话框的身影在项目中还是挺常见的,如首页中的栏目调整对话框,收藏歌单等。
然而Ant Design Vue提供的对话框组件并没有提供拖拽的功能,但这一功能在项目中又是不可缺少的,所以只好自己动手丰衣足食。
封装一个drop-modal主要分三步:
- 让drop-modal拥有拥有a-modal的API
- 在drop-modal上实现v-model
- modal首次显示后实例化Draggabilly
$attrs,$slots,$listeners
实现前两步的目的在于让书写drop-modal的语法和a-modal保持基本一致,其中第一步较为简单,新建drop-modal,其模板如下:
<template>
<a-modal
v-bind="{...$attrs,...$slots}"
v-on="$listeners"
>
<slot></slot>
</a-modal>
</template>
实现v-model
通常我们在a-modal上通过v-model绑定一个值,通过修改该值来控制对话框的显示隐藏,就像这样
<a-modal v-model="visible">
<p>contents</p>
</a-modal>
所以我们也应该在drop-modal实现上实现v-model。如果了解自定义组件的v-model是:value和@input的语法糖,实现起来也不难。
- 首先定义一个props
value
。 - 为了保持单向数据流,再定义一个计算属性
currentValue
,在其get方法中返回value,在set方法中触发自定义事件 - 最后将
currentValue
绑定在a-modal上即可。
核心代码如下:
<a-modal ... v-model="currentValue">
...
</a-modal>
computed: {
currentValue: {
get () {
return this.value
},
set (val) {
this.$emit(''input'', val)
}
}
}
实例化Draggabilly
最后一步也是最重要的一步,通过watch
监听 value
,当值为true时实例一个Draggabilly让modal变成可拖动。这一步需要注意4点:
- 确保在nextTick中实例化Draggabilly
- 仅在首次显示时实例化Draggabilly
- 确定可拖动的dom
- modal的嵌套情况
至此封装的drop-modal满足当前项目的所有需求,当然也有不足。
总结
封装drop-modal所涉及的vue核心知识点——$attrs
,$slots
,$listeners
,自定义组件的v-model的还原,计算属性保持数据单向,$nextTick。最终代码 drop-modal**
Vue中优雅“操作”dom之调整栏目顺序
动态组件
核心思路在于:动态组件 <component :is="componentName" />,通过操作数组navs的元素位置来控制栏目顺序。
navs中每个对象的key即componentName,hideMore来控制标题的右侧是否显示更多的链接。
navs: [
{
name: ''独家放送'',
key: ''privateContent'',
hideMore: true
},
{
name: ''最新音乐'',
key: ''newSong''
},
{
name: ''推荐歌单'',
key: ''playlist''
},
{
name: ''推荐MV'',
key: ''mv''
},
{
name: ''主播电台'',
key: ''dj''
}
]
<div v-for="nav in navs">
<component :is="nav.key" />
</div>
h5的拖拽api
接下来就是如何操作数组navs的问题了~ 通过h5的拖拽api改变元素位置并将新位置newNavs持久化保存,在页面初始化时使用newNavs渲染栏目组件即可。
此外还结合了 transition-group
组件,让栏目顺序变化有一个过渡效果,而这一过渡效果也很好的诠释了动画的重要意义--“解释刚刚发生了什么”
核心代码如下:
<div
v-for="nav in navs"
:key="nav.key"
draggable="true"
@dragstart="dragstart(nav)"
@dragenter="dragenter(nav)"
>
<span>{{nav.name}}</span>
<z-icon type="drag"></z-icon>
</div>
data () {
return {
oldNav: 0,
newNav: 0,
}
}
methods: {
dragstart (nav) {
this.oldNav = nav
},
dragenter (nav) {
this.newNav = nav
if (this.oldNav.name !== this.newNav.name) {
let oldIndex = this.navs.findIndex(nav => nav.name == this.oldNav.name)
let newIndex = this.navs.findIndex(nav => nav.name == this.newNav.name)
let newItems = [...this.navs]
newItems.splice(oldIndex, 1)
newItems.splice(newIndex, 0, this.oldNav)
this.navs = [...newItems]
window.localStorage.setItem(''nav'', JSON.stringify(this.navs))
}
}
}
最终实现的效果如下:
其他
项目中优雅操作dom的地方还很多,原理大同小异,即数据驱动。比如进度条组件<divref="buffered" :></div>
通过操作变量bufferedOffsetWidth
来控制缓冲条的width
又比如私人fm的歌曲卡片切换,篇幅有限不做过多介绍,详情请移步fm源码查看
音频可视化
AudioContext
音频可视化生动点长这样,还是挺炫酷的!!!
项目结合了两者实现了如下效果:射线和动态粒子,区别在于我的射线较细较短较密集(当然这些都是可控的),以及粒子是向圆内波动
音频的可视化要点在于使用canvas绘制基于AudioContext
获取到频谱数据。
首先获取频谱数据
// 获取API
let context = new AudioContext;
// 加载audio,可以是dom也可以是一个Audio的实例
let audio = new Audio("1.mp3");
// 创建节点
let source = context.createMediaElementSource(audio);
let analyser = context.createAnalyser();
// 连接:source → analyser → destination
source.connect(analyser);
analyser.connect(context.destination);
// 创建数据
let output = new Uint8Array(460);
// 获取频域数据
analyser.getByteFrequencyData(output)
打印output
,它长这样:
使用canvas绘制
首先绘制静态的外射线,注意观察每条射线
const { width, height } = document.getElementById(''canvas'')
const du = 3 // 圆心到两条射线距离所成的角度,即射线的间隙
const potInt = { x: width / 2, y: height / 2 } // 起始坐标,即画布中心
const R = 150 // 半径
const W = 4 // 射线的宽度
const L = 32 // 射线的长度
- 圆角:cxt.lineCap = ''round''
- 渐变:cxt.createLinearGradient(x1,y1,x2,y2)
- 起始点:
(Math.sin(((i * du) / 180) * Math.PI) * R + potInt.y,-Math.cos(((i * du) / 180) * Math.PI) * R + potInt.x)
- 结束点:
(Math.sin(((i * du) / 180) * Math.PI) * (R + L) + potInt.y, -Math.cos(((i * du) / 180) * Math.PI) * (R + L) + potInt.x)
其中i为循环360度的索引。确定了每条射线的起始点和结束点,也就确定了渐变的起始点和结束点。通过moveTo,lineTo绘制
紧接着将半径R扩大 let Rv = R + value
,先写死1再绘制一层纯色层叠加在渐变层之上。之后在requestAnimationFrame
的执行函数中根据频谱数据动态改变value即可实现动画效果,但要注意渐变层的射线应该总是大于纯色层射线L的长度。
canvas动画当然是少不了 cxt.clearRect(0, 0, width, height)
和 requestAnimationFrame
啦!动画及粒子向内的波动实现请参考musicView源码
除此之外还实现了另一种类似熔浆喷发的效果,也很nice。
渲染进程之间的即时通讯
项目一大重点难点是如何将store中歌词,播放状态等数据实时的在各窗体中共享。一开始想通过主进程来做中转,但主进程微笑而不失礼貌地婉拒了:“渲染进程能处理的事就不要拿来骚扰我啦,我很忙的!”。最后把目光投向了localstorage
。
// 监听storage改变时触发更新state
window.addEventListener(''storage'', () => {
initState()
})
// 订阅mutation改变storage
store.subscribe((mutation, state) => {
localStorage.setItem(STOREKEY, JSON.stringify(getState(state)))
})
其原理在于订阅mutation改变storage,监听storage触发更新state,通过书写一个vuex插件来实现这一功能,详情请查看 keep-state.js
usage:
在store入口文件引入keep-state,keep-state插件是一个函数,传入需要监听模块mudules执行函数,在初始化stroe时将函数的执行结果赋予plugins。
import persistStatePlugin from ''./plugins/keep-state''
const myPlugin = persistStatePlugin([''User'', ''play'', ''Localsong'', ''Setting'', ''Update''])
const store = new Vuex.Store({
...
plugins: [myPlugin]
})
electron实战之桌面歌词
实现桌面歌词需要注意以下几点:
- 透明窗体
- 窗口在别的窗口上面
- 可锁定(锁定后忽略窗口内的所有鼠标事件)
- 出现在屏幕的位置如何确定
通过设置transparent:true,alwaysOnTop: true可分别实现窗体透明和窗体置顶,其中透明窗体要注意html,body,#app等不能设置非透明的背景色。
通过 setignoremouseeventsignore api可切换锁定窗体。
至于窗体初始时的位置,默认是屏幕中央。我想让他水平居中,垂直在任务栏偏上一点,这就需要获取屏幕的高来做点文章了 const { height } = electron.screen.getPrimaryDisplay().workAreaSize
。
最终窗体初始化的核心代码如下:
const options = {
frame: false,
x: 0,
y: height - 150,
fullscreenable: false,
minimizable: false,
maximizable: false,
transparent: true,
alwaysOnTop: true,
skipTaskbar: true, // 任务栏中不显示窗口面板
closable: false
}
const winURL = process.env.NODE_ENV === ''development''
? `http://localhost:9080/#desktop-lyric`
: `file://${__dirname}/index.html#desktop-lyric`
let lyricWindow = new BrowserWindow(options)
lyricWindow.loadURL(winURL)
electron实战之mini模式
mini模式主要分为两部分:
- 主面板
- 当前播放列表面板
其中主面板又分三个面板:
- 歌曲缩略图,按住可拖动
- 歌曲信息及工具栏
- 相关操作面板
实现要点在于隐藏主窗体,显示mini窗体(320*50)。通过win.setBounds()在切换下拉列表时动态改变窗体大小
electron实战之自定义托盘菜单
通过electron Tray模块的实例的setContextMenu
方法创建的菜单是真的丑不忍睹..
如何自定义一个托盘菜单呢?就像这样:
答案之一就是通过一个窗体来模拟。通过监听托盘的右键点击事件切换菜单的显示隐藏即可,其中需要实时计算出每次菜单出现的位置及边界情况。
electron实战之自定义任务栏的缩略图工具栏
任务栏工具栏?长这样,包含标题缩略图,及歌曲的相关操作。
幸运的,electron提供相关API实现这一功能 缩略图工具栏
electron实战之拖拽播放
介绍
拖拽播放分三种:
- 将文件拖到主窗体内实现播放
- 将文件拖动到桌面上的快捷方式图标打开客户端并播放
- 客户端已经打开,将文件拖动到桌面上的快捷方式图标实现播放(不会打开第二个实例)
禁用默认行为
在实现之前请先看看默认将文件拖动到客户端会发生什么?
是的,默认和将文件拖动到Chrome浏览器是一样的,就像这样...
就猜到会是这样了...!
所以我们第一步就是要禁用掉这些默认行为:
window.ondragenter = (event) => {
event.preventDefault()
}
window.ondragover = (event) => {
event.preventDefault()
}
将文件拖到主窗体内实现播放
通过监听window的drop事件来实现我们的打开文件操作。这只是实现了拖拽播放中的第一种情况。
window.ondrop = openFilesOndrop
其他两种情况在windows平台上需要在process.argv上动动手脚。
将文件拖动到桌面上的快捷方式图标打开客户端并播放
先说说第二种情况,在主进程的appready
的事件回调中将process.argv赋予全局变量global global.argv = process.argv
,在渲染进程中通过electron的remote模块的getGlobal方法获取到argv
。process.argv初始化长这样:["E:\electron-vue-cloud-music\网易云音乐.exe"]
即客户端的可执行文件的路径。所以在执行handleWillOpenFiles
方法前判断一下数组长度。在handleWillOpenFiles
方法过滤出.mp3文件进行相关解析播放等操作。详情移步 createdInit
import { remote } from ''electron''
const startArgv = remote.getGlobal(''argv'')
if (startArgv.length > 1) {
handleWillOpenFiles(startArgv)
}
客户端已经打开,将文件拖动到桌面上的快捷方式图标实现播放
至于第三种情况和第二种大同小异,区别在于argv的参数的获取以及渲染进程如何拿到argv。对于argv的获取,在主进程的app的second-instance
监听回调中获取,通过自定义事件分发,渲染进程监听该自定义事件来接受。
// 主进程
app.on(''second-instance'', (event, argv, workingDirectory) => {
if (mainWindow) {
mainWindow.webContents.send(''open-files'', {argv})
}
})
// 渲染进程
import { ipcRenderer} from ''electron''
ipcRenderer.on(''open-files'', async (event, args) => {
let { argv } = args
handleWillOpenFiles(argv)
})
electron实战之自动/手动检查更新
当前自动更新已移除,简单说说如何实现手动检查更新,具体流程是这样的:
- 开发,commit
- npm version patch && git push origin master && git push origin --tags
- Travis CL,AppVeyor监测到master变化自动构建
- github上编辑发布远程版本
- 用户/客户端触发检查更新
- 客户端调用github API获取最新的远程版本号与本地版本号对比
- 如若需要更新显示更新窗体引导下载安装
下载完成后关闭窗体并打开下载文件进行安装
electron实战之Nedb数据库持久化
Nedb数据库 主要用来存储下载的歌曲列表及歌词。盗用官网介绍就是:
Embedded persistent or in memory database for Node.js, nw.js, Electron and browsers, 100% JavaScript, no binary dependency. API is a subset of MongoDB''s and it''s plenty fast.
本人4级水平简短白话翻译是为Electron而生,无依赖,快,使用和mongoDb差不多
electron实战之打包自定义安装路径,安装界面美化
自定义安装路径较为简单在package.json中找到build字段加入以下代码即可
"nsis": {
"oneClick": false, // 是否一键安装
"allowToChangeInstallationDirectory": true // 是否允许修改安装路径
}
自定义安装界面可通过一些开源工具来快捷实现如 NSIS-UI 简单实现了一下,效果还可以:
electron实战之自定义协议实现浏览器中启动客户端
通过app.setAsDefaultProtocolClient
可实现自定义协议在浏览器中唤起客户端,如果安装过了可尝试 打开electron云音乐
electron实战之离线/在线侦测与桌面通知
通过window的online
和offline
可监听网络状态。
通过navigator.onLine
可判断当前网络状态.
通过h5的Notification
可实现桌面通知,在window平台中使用请确保设置appId
Travis CL,AppVeyor自动构建
分享一篇阮一峰的一篇文章即可 持续集成
结语
当前项目只对window平台进行测试。
至此electron云音乐实战分享基本结束,项目中有趣的地方还有很多,但篇幅有限,不能面面俱到。本来还想说说那些令人敬礼的css但再不去打lol的衰减局就要掉峡谷宗师了!不排除有下集..第一次写文章,感谢各位看客老爷看到这里,谢谢。
最后唠叨一句:“觉得不错给我一个赞~”
其他界面预览(多图预警)
Ant Design Mobile Ant Design Mobile Ant Design 移动端设计规范的 React 实现
Ant Design Mobile Ant Design Mobile 介绍
Ant Design Mobile
Ant Design 移动端设计规范,一个基于
Preact/React/React Native 的 UI 组件库。antd-mobile 是 Ant Design 的移动规范的 React
实现,服务于蚂蚁及口碑无线业务。
-
基于 Ant Design 移动设计规范。
-
规则化的视觉样式配置,适应各类产品风格。
-
基于 React Native 的多平台支持。
-
使用 TypeScript 开发,提供类型定义文件。
-
iOS
-
Android 4.0+
适用场景
-
适合于中大型产品应用
-
适合于基于 react / preact / react-native 的多终端应用
-
适合不同 UI 风格的高度定制需求的应用
Ant Design Mobile Ant Design Mobile 官网
https://mobile.ant.design/index-cn
Ant Design of Vue select框获取key和name的问题
Ant Design of Vue select框获取key和name
加入label-in-value这个属性
<a-form-item label="分类"> <a-select placeholder="请选择分类" label-in-value v-decorator="[''knowledgeunit'', { rules: [{ required: true, message: ''请选择分类'' }] }]" > <a-select-option v-for="(calssitem, index) in classflyData" :key="index" :value="calssitem.Code"> {{ calssitem.Name }} </a-select-option> </a-select> </a-form-item>
获取到的value 就会变成 {key: 1, lable: ''名字''} 的形式
获取值的时候可以这样获取
this.addResourceForm.validateFields((err, values) => { if (err && this.newChange.length > 0) { return } const saveObj = {} saveObj.knowledgeunit = values.knowledgeunit.key // 获取的值 saveObj.source = values.knowledgeunit.label // 获取的名称 })
我的记录
还有一种方法
你如果想获取怎个对象,怎么获取呢?
<a-form-item label="分类"> <a-select placeholder="请选择分类" @change="onChange" v-decorator="[''knowledgeunit'', { rules: [{ required: true, message: ''请选择分类'' }] }]" > <a-select-option v-for="(calssitem, index) in classflyData" :key="index" :value="calssitem.Code"> {{ calssitem.Name }} </a-select-option> </a-select> </a-form-item>
加一个onChange方法,根据下标获取对应的对象
onChange (item) { const obj = this.list[item] console.log(obj) }
Ant Design Vue使用select出现的问题
1.select下拉菜单滚动条滚动后,自动弹回到顶部
解决方法:
a-select-option 使用v-for渲染时,key值不能重复或者为null
2.下拉列表在局部滚动时不跟随,与select框分离
解决方法:
<a-select :getPopupContainer="(triggerNode)=>{ return triggerNode.parentNode || document.body;}" >
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
- Vue中keyup.enter和blur事件冲突的问题及解决
- vue中@keyup.enter失效问题及解决
- vue对象添加属性(key:value)、显示和删除属性方式
- Vue深入理解之v-for中key的真正作用
- Vue开发实例探究key的作用详解
ant design of vue 中的select问题
在做项目中使用ant design of vue 的ui框架,
使用select做省市区联动的时候,发现v-model和placehoder不能共用。
解决办法:
<a-select v-model="provinceId" placeholder="请选择省份"@change="provinceChanged" allowClear>
<a-select-option v-for="item in provinces" :key="item.id">{{item.name}}</a-select-option>
</a-select>
<a-select v-model="cityId" placeholder="请选择城市"@change="cityChanged" allowClear>
<a-select-option v-for="item in cities" :key="item.id">{{item.name}}</a-select-option>
</a-select>
js:
一定要记住provinceId,和cityId 默认要设置为undefiend,否则不会显示placeholder内容
我们今天的关于Ant Design Vue中TreeSelect详解和ant design vue tree的分享就到这里,谢谢您的阅读,如果想了解更多关于2019Electron+Vue+Ant Design Vue仿网易云音乐windows客户端实战分享、Ant Design Mobile Ant Design Mobile Ant Design 移动端设计规范的 React 实现、Ant Design of Vue select框获取key和name的问题、ant design of vue 中的select问题的相关信息,可以在本站进行搜索。
本文标签: