This commit is contained in:
songwanli2025@163.com 2019-12-23 17:21:05 +08:00
parent 20c535233e
commit fabd5e02a2
21 changed files with 413 additions and 107 deletions

View File

@ -1,4 +1,4 @@
# Basic
# Debug
```html
<n-card title="Random String Logs" :segmented="{
header: 'soft',
@ -7,8 +7,7 @@
<n-log
style="margin-top: -12px; margin-bottom: -12px;"
:log="log"
@reach-top="handleReachTop"
@reach-bottom="handleReachBottom"
@require-more="handleRequireMore"
:loading="loading"
trim
/>
@ -38,19 +37,15 @@ export default {
clear () {
this.log = ''
},
handleReachTop () {
handleRequireMore (from) {
if (this.loading) return
this.loading = true
setTimeout(() => {
if (from === 'top') {
this.log = log() + this.log
this.loading = false
}, 1000)
},
handleReachBottom () {
if (this.loading) return
this.loading = true
setTimeout(() => {
} else if (from === 'bottom') {
this.log = this.log + log()
}
this.loading = false
}, 1000)
}

View File

@ -0,0 +1,55 @@
# Event
Log has `require-more`, `reach-top` and `reach-bottom` event. Note that even if logs are scrolled to top or bottom, when you wheel to the same direction, `require-more` will still be triggered. If you don't want to trigger handler when logs are at top or bottom. Use `reach-top` or `reach-bottom` instead.
```html
<n-log
:log="log"
@require-more="handleRequireMore"
@reach-top="handleReachTop"
@reach-bottom="handleReachBottom"
:loading="loading"
trim
/>
```
```js
function log () {
const l = []
for (let i = 0; i < 40; ++i) {
l.push((Math.random()).toString(16))
}
return l.join('\n') + '\n'
}
export default {
data () {
return {
loading: false,
log: log()
}
},
methods: {
clear () {
this.log = ''
},
handleRequireMore (from) {
this.$NMessage.info('Require More from ' + from)
if (this.loading) return
this.loading = true
setTimeout(() => {
if (from === 'top') {
this.log = log() + this.log
} else if (from === 'bottom') {
this.log = this.log + log()
}
this.loading = false
}, 1000)
},
handleReachTop () {
this.$NMessage.info('Reach Top')
},
handleReachBottom () {
this.$NMessage.info('Reach Bottom')
}
}
}
```

View File

@ -0,0 +1,53 @@
# Highlight
Before you use highlight, see Note section of the page to make sure you won't miss messages that are important to make it work.
```html
<n-log
:log="log"
@require-top="handlerequireTop"
@require-bottom="handlerequireBottom"
:loading="loading"
language="naive-log"
trim
/>
```
```js
function log () {
const l = []
for (let i = 0; i < 40; ++i) {
l.push((Math.random()).toString(16))
}
return l.join('\n') + '\n'
}
export default {
data () {
return {
loading: false,
log: log()
}
},
methods: {
clear () {
this.log = ''
},
handlerequireTop () {
if (this.loading) return
this.loading = true
setTimeout(() => {
this.log = log() + this.log
this.loading = false
}, 1000)
},
handlerequireBottom () {
if (this.loading) return
this.loading = true
setTimeout(() => {
this.log = this.log + log()
this.loading = false
}, 1000)
}
}
}
```

View File

@ -1,6 +1,32 @@
# Log
<!--single-column-->
<n-alert title="Note" type="warning">
Due to package size, Naive UI doesn't include highlight.js. If you want highlight logs, make sure you have set highlightjs before using it.
</n-alert>
In hightlight demo, we defined a language called `naive-log` which will highlight all the numbers of line. The following code shows how we defined it. If you want to know more about hightlight.js, see <a href="https://highlightjs.org/">hightlight.js</a> and <a href="https://highlightjs.readthedocs.io/en/latest/index.html">highlight.js developer documentation</a>
```js
...
hljs.registerLanguage('naive-log', () => ({
contains: [
{
className: 'number',
begin: /\d+/
}
]
}))
Vue.use(NaiveUI)
NaiveUI.setHljs(hljs)
...
```
## Demos
```demo
basic
size
event
scroll
highlight
loading
```

View File

@ -1,19 +1,10 @@
# Loading
```html
<n-switch v-model="loading" />
<n-card title="Random String Logs" :segmented="{
header: 'soft',
content: 'hard'
}">
<n-log
style="margin-top: -12px; margin-bottom: -12px;"
<n-log
:loading="loading"
:log="log"
/>
<template v-slot:action>
Loading?
</template>
</n-card>
/>
```
```js

View File

@ -0,0 +1,69 @@
# Scroll
You can easily make log scroll to top or bottom. Also you can make the scroll action silent (don't trigger events of Log of this scroll action).
```html
<n-button-group>
<n-button @click="scrollTo('bottom', false)">Scroll To Bottom</n-button>
<n-button @click="scrollTo('bottom', true)">Scroll To Bottom (silent)</n-button>
<n-button @click="scrollTo('top', false)">Scroll To Top</n-button>
<n-button @click="scrollTo('top', true)">Scroll To Top (silent)</n-button>
</n-button-group>
<n-log
ref="log"
:log="log"
@require-more="handleRequireMore"
@reach-top="handleReachTop"
@reach-bottom="handleReachBottom"
:loading="loading"
trim
/>
```
```js
function log () {
const l = []
for (let i = 0; i < 40; ++i) {
l.push((Math.random()).toString(16))
}
return l.join('\n') + '\n'
}
export default {
data () {
return {
loading: false,
log: log()
}
},
methods: {
clear () {
this.log = ''
},
handleRequireMore (from) {
this.$NMessage.info('Require More from ' + from)
if (this.loading) return
this.loading = true
setTimeout(() => {
if (from === 'top') {
this.log = log() + this.log
} else if (from === 'bottom') {
this.log = this.log + log()
}
this.loading = false
}, 1000)
},
handleReachTop () {
this.$NMessage.info('Reach Top')
},
handleReachBottom () {
this.$NMessage.info('Reach Bottom')
},
scrollTo(to, dismissEvent = false) {
if (to === 'bottom') {
this.$refs.log.scrollToBottom(dismissEvent)
} else {
this.$refs.log.scrollToTop(dismissEvent)
}
}
}
}
```

View File

@ -0,0 +1,11 @@
# Size
Use `rows` to change the size of log.
```html
<n-log :rows="5" :log="`1
2
3
4
5
6`"/>
```

View File

@ -0,0 +1,22 @@
# Columns
| Property | Description | Type | Default |
| :--------------- | :-------------------------------------------------------------------------------------------------------- | :---------------------------- | :------ |
| align | specify which way that column is aligned | 'left' \| 'right' \| 'center' | 'left' |
| ellipsis | ellipsize cell content,recommended when no property:render is used | boolean | false |
| className | className of this column | boolean | false |
| title | Title of this column | String | - |
| key | Unique key of this column,**required** | string | - |
| render | Renderer of the table cell. The return value should be a VueNode | Function(h, record, index) {} | - |
| renderHeader | Renderer of the table header cell. The return value should be a VueNode | Function(h, column) {} | - |
| sortable | use column sort, need property:sorter | boolean | false |
| sorter | Sort function for local sort, see Array.sort's compareFunction.If you need network sorter,set to `custom` | Function \| 'custom' | - |
| defaultSortOrder | default sort order | 'ascend' \| 'descend' | - |
| filterable | use filter | boolean | false |
| filter | Filter function for local filter.If you need network sorter,set to `custom` | Function \| 'custom' | - |
| filterMultiple | Whether multiple filters can be selected | boolean | false |
| defaultFilter | default filter selected | String | - |
| filterItems | Filter menu config,format as [{label,value}] | object[] | - |
| asyncFilterItems | async filter menu config ,Function returns [{label,value}] | Function | - |
| fixed | Set column to be fixed: 'left' 'right' | 'left'\| 'right' | - |
| width | Width of this column | string | number | - |

View File

@ -24,24 +24,6 @@ fixedHeaderColumn
ellipsis
renderHeader
bestPractices
property
column
```
## Column
| Property | Description | Type | Default |
| :--------------- | :-------------------------------------------------------------------------------------------------------- | :---------------------------- | :------ |
| align | specify which way that column is aligned | 'left' \| 'right' \| 'center' | 'left' |
| ellipsis | ellipsize cell content,recommended when no property:render is used | boolean | false |
| className | className of this column | boolean | false |
| title | Title of this column | String | - |
| key | Unique key of this column,**required** | string | - |
| render | Renderer of the table cell. The return value should be a VueNode | Function(h, record, index) {} | - |
| sortable | use column sort, need property:sorter | boolean | false |
| sorter | Sort function for local sort, see Array.sort's compareFunction.If you need network sorter,set to `custom` | Function \| 'custom' | - |
| defaultSortOrder | default sort order | 'ascend' \| 'descend' | - |
| filterable | use filter | boolean | false |
| filter | Filter function for local filter.If you need network sorter,set to `custom` | Function \| 'custom' | - |
| filterMultiple | Whether multiple filters can be selected | boolean | false |
| defaultFilter | default filter selected | String | - |
| filterItems | Filter menu config,format as [{label,value}] | object[] | - |
| asyncFilterItems | async filter menu config ,Function returns [{label,value}] | Function | - |

View File

@ -0,0 +1,11 @@
# Property
| Property | Description | Type | Default |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------- | :------ |
| data | Structured data displayed. | Array | - |
| columns | Column configuration. Details are mentioned below. | Array | - |
| max-height | The max-height of the table. Unit: px / When this prop is set, if the content height is larger then the set value, the header will be fixed at the top. | Number \| String | - |
| row-class-name | Callback function for row's class name. Accept two arguments: -params: current row's data. -index: current row's index | Function | - |
| loading | Whether the table is loading. | Boolean | false |
| scroll-x | Set horizontal scrolling, can also be used to specify the width and height of the scroll area | number | - |
| pagination | Config of pagination. | object | - |

View File

@ -106,6 +106,14 @@ import cpp from 'highlight.js/lib/languages/cpp'
hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('python', python)
hljs.registerLanguage('cpp', cpp)
hljs.registerLanguage('naive-log', () => ({
contains: [
{
className: 'number',
begin: /\d+/
}
]
}))
Vue.use(VueI18n)
Vue.use(VueRouter)

View File

@ -1,6 +1,6 @@
{
"name": "naive-ui",
"version": "0.6.0",
"version": "0.6.3",
"description": "",
"main": "index.js",
"scripts": {

View File

@ -183,7 +183,7 @@ export default {
}
},
watch: {
'$store.state.currentHoverRow' (index, oldIndex) {
'$tableStore.state.currentHoverRow' (index, oldIndex) {
const hoverClassName = 'n-table__tr--hover'
const rowsDom = this.$el.querySelectorAll('table tr')
const oldRowDom = rowsDom[oldIndex]
@ -206,16 +206,16 @@ export default {
},
methods: {
onMouseEnter (e) {
this.$store.commit('currentTableEl', e.currentTarget)
this.$tableStore.commit('currentTableEl', e.currentTarget)
},
onMouseLeave (e) {
this.$store.commit('currentTableEl', null)
this.$tableStore.commit('currentTableEl', null)
},
onRowHover (e, rowData, index) {
this.$store.commit('currentHoverRow', index)
this.$tableStore.commit('currentHoverRow', index)
},
onRowLeave (e, rowData) {
this.$store.commit('currentHoverRow', null)
this.$tableStore.commit('currentHoverRow', null)
},
computeCustomWidthStl (column) {
if (column.width) {

View File

@ -17,7 +17,7 @@
v-for="(column, i) in columns"
:key="i"
:style="computeCustomWidthStl(column)"
>
/>
<!-- <col v-if="scrollBarWidth" :width="scrollBarWidth" > -->
</colgroup>
@ -34,7 +34,7 @@
<!-- 当前页全选 -->
<n-checkbox
v-if="column.type === 'selection'"
:checked="$store.state.selectedAllChecked"
:checked="$tableStore.state.selectedAllChecked"
:indeterminate="isCheckedBoxAllIndeterminate"
@change="selectedAllCheckedChange"
@click.native="onAllCheckboxesClick"
@ -238,7 +238,7 @@ export default {
this.$emit('on-checkbox-all', this.currentPageAllSelect)
},
selectedAllCheckedChange (v) {
this.$store.commit('selectedAllChecked', v)
this.$tableStore.commit('selectedAllChecked', v)
},
onFilter (value, column) {
this.$emit('on-filter', value, column)

View File

@ -145,7 +145,7 @@
import { noopFn } from '../../../utils/index'
import withapp from '../../../mixins/withapp'
import themeable from '../../../mixins/themeable'
import { Store, storageMixin } from '../store'
import { storageMixin } from '../store'
import BaseTable from '../baseTable/baseTable'
const sortOrderMap = {
@ -160,9 +160,6 @@ const sortOrderReverseMap = {
}
export default {
store () {
return new Store()
},
name: 'NAdvancedTable',
components: {
// searchInput,
@ -479,7 +476,7 @@ export default {
this.checkBoxes = []
this.disabledCheckBox = []
this.currentPageAllSelect = false
this.$store.commit('selectedAllChecked', false)
this.$tableStore.commit('selectedAllChecked', false)
this.computeScollBar()
},
@ -580,7 +577,7 @@ export default {
})
},
onBodyScrolll (event) {
const currentEl = this.$store.state.currentTableEl
const currentEl = this.$tableStore.state.currentTableEl
const scrollEls = [
this.fixedLeftTBodyEl,
this.mainTBodyEl,
@ -721,7 +718,7 @@ export default {
(this.currentPageSelectedLen > 0 &&
this.currentPageSelectedLen === this.showingData.length) ||
this.isCheckedBoxAllIndeterminate
this.$store.commit('selectedAllChecked', needChecked)
this.$tableStore.commit('selectedAllChecked', needChecked)
},
computePageDivideData (data) {
if (this.pagination && this.pagination.limit && !this.pagination.custom) {
@ -767,7 +764,7 @@ export default {
},
onAllCheckboxesClick () {
this.showingData.forEach(item => {
this.checkBoxes[item._index] = this.$store.state.selectedAllChecked
this.checkBoxes[item._index] = this.$tableStore.state.selectedAllChecked
})
this.checkBoxes = [].concat(this.checkBoxes)
},

View File

@ -2,8 +2,8 @@
* @Author: Volankey@gmail.com
* @Company: Tusimple
* @Date: 2019-10-25 11:31:12
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-11-07 11:13:03
* @LastEditors : Jiwen.bai
* @LastEditTime : 2019-12-18 17:46:19
*/
let Vue = null
export class Store {
@ -35,11 +35,10 @@ function vuexInit () {
Vue = _Vue
}
// store injection
if (options.store) {
this.$store =
typeof options.store === 'function' ? options.store() : options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
if (options.parent && options.parent.$tableStore) {
this.$tableStore = options.parent.$tableStore
} else if (!this.$tableStore) {
this.$tableStore = new Store()
}
}
export const storageMixin = {

View File

@ -1,6 +1,6 @@
<template>
<div
class="n-log"
class="n-log n-code"
:class="{
[`n-${synthesizedTheme}-theme`]: synthesizedTheme
}"
@ -35,6 +35,11 @@ export default {
NLogLine,
NFadeInHeightExpandTransition
},
provide () {
return {
NLog: this
}
},
mixins: [ withapp, themeable ],
props: {
loading: {
@ -49,6 +54,10 @@ export default {
type: String,
default: null
},
fontSize: {
type: Number,
default: 14
},
lines: {
type: Array,
default: () => []
@ -57,9 +66,13 @@ export default {
type: Number,
default: 1.25
},
language: {
type: String,
default: null
},
rows: {
type: Number,
default: 20
default: 15
},
offsetTop: {
type: Number,
@ -77,22 +90,19 @@ export default {
data () {
return {
memorizedScrollTop: 0,
dismissEvent: false,
memorizedScrollBottom: null
}
},
computed: {
paddingStyleHeight () {
return `${this.lineHeight}em`
highlight () {
return this.language !== null
},
styleHeight () {
return `${this.rows * this.lineHeight}em`
},
processedLog () {
if (this.trim && this.log) return this.log.trim()
else return this.log
const lineHeight = Math.floor(this.fontSize * this.lineHeight)
return `calc(${this.rows * lineHeight}px)`
},
synthesizedLines () {
if (this.lines.length) return this.lines
if (!this.log) return []
return this.log.split('\n')
}
@ -102,15 +112,33 @@ export default {
return this.hljs || this.$naive.hljs
},
handleScroll (e, container, content) {
if (this.dismissEvent) {
this.$nextTick().then(() => {
this.dismissEvent = false
})
return
}
const containerHeight = container.offsetHeight
const containerScrollTop = container.scrollTop
const contentHeight = content.offsetHeight
const scrollTop = containerScrollTop
const scrollBottom = contentHeight - containerScrollTop - containerHeight
if (scrollTop <= this.offsetTop) this.$emit('reach-top')
if (scrollBottom <= this.offsetBottom) this.$emit('reach-bottom')
if (scrollTop <= this.offsetTop) {
this.$emit('require-more', 'top')
this.$emit('reach-top')
}
if (scrollBottom <= this.offsetBottom) {
this.$emit('require-more', 'bottom')
this.$emit('reach-bottom')
}
},
handleWheel (e) {
if (this.dismissEvent) {
this.$nextTick().then(() => {
this.dismissEvent = false
})
return
}
if (this.$refs.scrollbar && this.$refs.scrollbar.$refs.scrollContainer) {
const container = this.$refs.scrollbar.$refs.scrollContainer
const containerHeight = container.offsetHeight
@ -121,10 +149,26 @@ export default {
const scrollTop = containerScrollTop
const scrollBottom = contentHeight - containerScrollTop - containerHeight
const deltaY = e.deltaY
if (scrollTop === 0 && deltaY < 0) this.$emit('reach-top')
if (scrollBottom === 0 && deltaY > 0) this.$emit('reach-bottom')
if (scrollTop === 0 && deltaY < 0) this.$emit('require-more', 'top')
if (scrollBottom === 0 && deltaY > 0) this.$emit('require-more', 'bottom')
}
}
},
scrollToTop (dismissEvent = false) {
this.scrollTo(dismissEvent, 'top')
},
scrollToBottom (dismissEvent = false) {
this.scrollTo(dismissEvent, 'bottom')
},
scrollTo (dismissEvent = false, to) {
if (dismissEvent) {
this.dismissEvent = true
}
if (to === 'bottom') {
this.$refs.scrollbar.scrollToBottom()
} else {
this.$refs.scrollbar.scrollToTop()
}
}
}
}

View File

@ -1,5 +1,5 @@
<template>
<pre class="n-log__line" />
<pre class="n-log__line">{{ highlight ? null : line }}</pre>
</template>
<script>
@ -8,23 +8,52 @@ export default {
line: {
type: String,
default: null
}
},
language: {
type: String,
default: 'javascript'
inject: {
NLog: {
default: null
}
},
computed: {
highlight () {
return this.NLog.highlight
},
language () {
return this.NLog.language
},
trim () {
return this.NLog.trim
},
trimedLine () {
if (this.trim) return (this.line || '').trim()
else return this.line
}
},
watch: {
line (value) {
this.$el.innerHTML = this.getHljs().highlight(this.language, value).value
this.setInnerHTML()
}
},
mounted () {
this.$el.innerHTML = this.getHljs().highlight(this.language, this.line).value
this.setInnerHTML()
},
methods: {
setInnerHTML () {
if (this.highlight) {
this.$el.innerHTML = this.generateCodeHTML(this.language, this.trimedLine, false).content
}
},
getHljs () {
return this.hljs || this.$naive.hljs
},
generateCodeHTML (language, code, trim) {
const languageValid = !!(language && this.getHljs().getLanguage(language))
if (trim) code = code.trim()
return {
valid: languageValid,
content: this.getHljs().highlight(language, code).value
}
}
}
}

View File

@ -205,6 +205,20 @@ export default {
this.showHorizontalScrollbar = true
this.showVeriticalScrollbar = true
},
scrollToTop (smooth = false) {
if (this.$refs.scrollContainer) {
this.$refs.scrollContainer.scrollTo({
top: 0
})
}
},
scrollToBottom (smooth = false) {
if (this.$refs.scrollContainer) {
this.$refs.scrollContainer.scrollTo({
top: this.$refs.scrollContent.offsetHeight
})
}
},
scrollToElement (el) {
if (el.offsetTop < this.$refs.scrollContainer.scrollTop) {
this.$refs.scrollContainer.scrollTo({

View File

@ -1,5 +1,13 @@
@import "./mixins/mixins.scss";
@include themes-mixin {
@include b(code) {
[class^=hljs] {
color: $--n-secondary-text-color;
}
}
}
@include b(code) {
margin: 0;
font-size: 14px;
@ -12,7 +20,6 @@
display: block;
overflow-x: auto;
padding: 0.5em;
color: #383a42;
background: #fafafa;
}

View File

@ -7,27 +7,20 @@
font-size: 14px;
color: $--n-secondary-text-color;
box-sizing: border-box;
transition: border-color .3s $default-cubic-bezier;
@include m(top-bordered) {
border-top: 1px solid $--n-border-color;
}
@include m(bottom-bordered) {
border-bottom: 1px solid $--n-border-color;
}
transition: border-color .3s $default-cubic-bezier, color .3s $default-cubic-bezier;
@include b(scrollbar) {
@include b(scrollbar-content) {
padding-top: 8px;
padding-bottom: 8px;
// padding-top: 8px;
// padding-bottom: 8px;
overflow: hidden;
}
@include b(scrollbar-rail) {
@include m(vertical) {
top: 8px;
bottom: 8px
// @include m(vertical) {
// top: 8px;
// bottom: 8px
// }
}
}
}
@include e(lines) {
margin: 0;
white-space: pre-wrap;
@ -37,9 +30,9 @@
}
@include b(log-loader) {
@include fade-in-width-expand-transition($duration: .3s, $delay: 0s);
transition: color .3s $default-cubic-bezier, background-color .3s $default-cubic-bezier;
box-sizing: border-box;
border: 1px solid $--n-border-color;
// box-shadow: $--popover-box-shadow;
position: absolute;
right: 16px;
top: 8px;