1
0

feat: add clampchange event, revert raf

This commit is contained in:
Justineo
2020-03-28 01:48:18 +08:00
parent 357bd0f076
commit 34cc83441b
7 changed files with 5006 additions and 3031 deletions

View File

@@ -1,3 +1,7 @@
## 0.3.0
* Add `clampchange` event.
## 0.2.2
* Preserve at lease a single line of content when even a single line would exceeds `max-height`.

View File

@@ -1,5 +1,5 @@
module.exports = {
presets: [
'@vue/app'
'@vue/cli-plugin-babel/preset'
]
}

7783
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +1,56 @@
{
"name": "vue-clamp",
"version": "0.2.2",
"license": "MIT",
"version": "0.3.0",
"description": "Clamping multiline text with ease.",
"scripts": {
"serve": "vue-cli-service serve",
"build:demo": "vue-cli-service build",
"lint": "vue-cli-service lint",
"build": "NODE_ENV=production rollup -c",
"lint": "vue-cli-service lint",
"build:demo": "vue-cli-service build",
"prepublishOnly": "cp ./src/components/Clamp.js .",
"publish": "rm ./Clamp.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Justineo/vue-clamp.git"
"main": "dist/vue-clamp.js",
"module": "Clamp.js",
"dependencies": {
"core-js": "^3.6.4",
"resize-detector": "^0.1.10"
},
"devDependencies": {
"@rollup/plugin-buble": "^0.21.1",
"@rollup/plugin-node-resolve": "^7.1.1",
"@vue/cli-plugin-babel": "^4.2.3",
"@vue/cli-plugin-eslint": "^4.2.3",
"@vue/cli-service": "^4.2.3",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.1",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-vue": "^6.2.2",
"highlight.js": "^9.18.1",
"prettier": "^2.0.2",
"prettier-eslint": "^9.0.1",
"qs": "^6.9.3",
"rollup": "^2.2.0",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-vue": "^5.1.6",
"spectre.css": "^0.5.8",
"stylus": "^0.54.7",
"stylus-loader": "^3.0.2",
"vue": "^2.6.11",
"vue-template-compiler": "^2.6.11"
},
"peerDependencies": {
"vue": "^2.5.17"
},
"bugs": {
"url": "https://github.com/Justineo/vue-clamp/issues"
},
"homepage": "https://justineo.github.io/vue-clamp/demo/",
"main": "dist/vue-clamp.js",
"module": "Clamp.js",
"dependencies": {
"resize-detector": "^0.1.10"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-service": "^3.11.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.3",
"eslint": "^5.16.0",
"eslint-config-prettier": "^4.3.0",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-vue": "^5.2.3",
"highlight.js": "^9.15.10",
"prettier": "^1.18.2",
"prettier-eslint": "^8.8.2",
"qs": "^6.8.0",
"rollup": "^0.68.2",
"rollup-plugin-buble": "^0.19.8",
"rollup-plugin-node-resolve": "^4.2.4",
"rollup-plugin-terser": "^3.0.0",
"rollup-plugin-vue": "^4.7.2",
"spectre.css": "^0.5.8",
"stylus": "^0.54.7",
"stylus-loader": "^3.0.2",
"vue": "^2.6.10",
"vue-template-compiler": "^2.6.10"
},
"peerDependencies": {
"vue": "^2.5.17"
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/Justineo/vue-clamp.git"
}
}

View File

@@ -1,7 +1,7 @@
import vue from 'rollup-plugin-vue'
import buble from 'rollup-plugin-buble'
import buble from '@rollup/plugin-buble'
import { terser } from 'rollup-plugin-terser'
import resolve from 'rollup-plugin-node-resolve'
import resolve from '@rollup/plugin-node-resolve'
export default {
input: 'src/components/Clamp.js',

View File

@@ -32,7 +32,6 @@
GitHub
</a>
</p>
<h2 id="features"><a href="#features">#</a> {{ zh ? '功能' : 'Features' }}</h2>
<ul>
<li>{{ zh ? '可以选择限制行数与/或最大高度,无需指定行高。' : 'Clamps text with max lines and/or max height. No need to specify line height.' }}</li>
@@ -40,7 +39,6 @@
<li>{{ zh ? '支持展开/收起被截断部分内容。' : 'The clamped text can be expanded/collapsed.' }}</li>
<li>{{ zh ? '支持自定义截断文本前后内容,并且进行响应式更新。' : 'Customizable and responsive content before/after clamped text.' }}</li>
</ul>
<h2 id="demo"><a href="#demo">#</a> Demo</h2>
<div
class="divider text-center"
@@ -224,6 +222,88 @@
</template>
</v-clamp>
</section>
<div
class="divider text-center"
data-content=" `clampchange` event"
/>
<section class="case">
<div class="form-horizontal">
<div class="form-group">
<label
class="form-label col-5 col-sm-12"
for="lines3"
>
{{ zh ? '最大行数' : 'Max lines' }}
</label>
<div
class="col-7 col-sm-12"
>
<input
id="lines3"
v-model.number="lines3"
class="form-input"
type="number"
min="1"
max="8"
step="1"
>
</div>
</div>
<div class="form-group">
<label
class="form-label col-5 col-sm-12"
for="width3"
>
{{ zh ? '容器宽度' : 'Container width' }}
</label>
<div
class="col-7 col-sm-12 tooltip"
:data-tooltip="`${width3}px`"
>
<input
id="width3"
v-model="width3"
class="slider"
type="range"
min="240"
max="600"
>
</div>
</div>
<div
v-if="!zh"
class="form-group"
>
<div class="col-5 col-sm-12">
<label class="form-checkbox">
<input
v-model="hyphens3"
type="checkbox"
>
<i class="form-icon"/>
CSS <code>hyphens</code>
</label>
</div>
</div>
</div>
<v-clamp
:class="{
demo: true,
hyphens: hyphens3
}"
:max-lines="lines3"
autoresize
:style="{
width: `${width3}px`
}"
@clampchange="clamped3 = $event"
>
{{ zh ? textZh : text }}
</v-clamp>
<p class="mt-2">
{{ zh ? '截断状态:' + (clamped3 ? '已截断' : '未截断') : 'Clamped: ' + (clamped3 ? 'Yes' : 'No')}}
</p>
</section>
<h2 id="usage"><a href="#usage">#</a> {{ zh ? '使用方法' : 'Usage' }}</h2>
<div
class="divider text-center"
@@ -392,6 +472,19 @@ export default {
</li>
</ul>
</section>
<div
class="divider text-center"
data-content=" Events"
/>
<section>
<ul>
<li>
<p><code>clampchange</code></p>
<p>{{ zh ? '截断状态变化时触发。' : 'Emitted when clamp state changes.' }}</p>
<p>{{ parameterText }}<code>(clamped: Boolean)</code></p>
</li>
</ul>
</section>
<footer>
<p v-if="zh">由 <a href="https://github.com/Justineo">@Justineo</a> 创作</p>
<p v-else>Made by <a href="https://github.com/Justineo">@Justineo</a>.</p>
@@ -417,9 +510,9 @@ hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('diff', diff)
hljs.registerLanguage('shell', shell)
let search = location.search.replace(/^\?/, '')
let query = qs.parse(search)
let zh = query.lang === 'zh'
const search = location.search.replace(/^\?/, '')
const query = qs.parse(search)
const zh = query.lang === 'zh'
export default {
name: 'app',
@@ -435,6 +528,10 @@ export default {
height: 'calc(48px + 12em)',
width2: 600,
hyphens2: true,
lines3: 5,
width3: 600,
hyphens3: true,
clamped3: false,
text:
'Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.',
textZh:
@@ -446,6 +543,9 @@ export default {
computed: {
defaultText () {
return this.zh ? '默认值:' : 'Default:'
},
parameterText () {
return this.zh ? '回调参数:' : 'Callback parameter list:'
}
},
watch: {
@@ -548,6 +648,7 @@ summary
display flex
align-items center
margin-bottom 0.5em
cursor pointer
h4
margin 0

View File

@@ -1,8 +1,5 @@
import { addListener, removeListener } from 'resize-detector'
const UPDATE_TRIGGERS = ['maxLines', 'maxHeight', 'ellipsis', 'isClamped']
const INIT_TRIGGERS = ['tag', 'text', 'autoresize']
export default {
name: 'vue-clamp',
props: {
@@ -46,7 +43,7 @@ export default {
if (this.localExpanded) {
return null
}
let { maxHeight } = this
const { maxHeight } = this
if (!maxHeight) {
return null
}
@@ -57,13 +54,6 @@ export default {
expanded (val) {
this.localExpanded = val
},
isClamped: {
handler (val) {
this.$nextTick()
.then(() => this.$emit('change', val))
},
immediate: true
},
localExpanded (val) {
if (val) {
this.clampAt(this.text.length)
@@ -73,18 +63,19 @@ export default {
if (this.expanded !== val) {
this.$emit('update:expanded', val)
}
},
isClamped: {
handler (val) {
this.$nextTick(() => this.$emit('clampchange', val))
},
immediate: true
}
},
mounted () {
this.init()
INIT_TRIGGERS.forEach(prop => {
this.$watch(prop, this.init)
})
UPDATE_TRIGGERS.forEach(prop => {
this.$watch(prop, this.update)
})
this.$watch(vm => [vm.maxLines, vm.maxHeight, vm.ellipsis, vm.isClamped].join(), this.update)
this.$watch(vm => [vm.tag, vm.text, vm.autoresize].join(), this.init)
},
updated () {
this.text = this.getText()
@@ -95,7 +86,7 @@ export default {
},
methods: {
init () {
let contents = this.$slots.default
const contents = this.$slots.default
if (!contents) {
return
}
@@ -105,12 +96,9 @@ export default {
this.cleanUp()
if (this.autoresize) {
let resizeCallback = () => {
window.requestAnimationFrame(this.update)
}
addListener(this.$el, resizeCallback)
addListener(this.$el, this.update)
this.unregisterResizeCallback = () => {
removeListener(this.$el, resizeCallback)
removeListener(this.$el, this.update)
}
}
this.update()
@@ -156,7 +144,7 @@ export default {
},
getText () {
// Look for the first non-empty text node
let [content] = (this.$slots.default || []).filter(
const [content] = (this.$slots.default || []).filter(
node => !node.tag && !node.isComment
)
return content ? content.text : ''
@@ -189,12 +177,12 @@ export default {
}
},
search (...range) {
let [from = 0, to = this.offset] = range
const [from = 0, to = this.offset] = range
if (to - from <= 3) {
this.stepToFit()
return
}
let target = Math.floor((to + from) / 2)
const target = Math.floor((to + from) / 2)
this.clampAt(target)
if (this.isOverflow()) {
this.search(from, target)
@@ -209,7 +197,7 @@ export default {
}
},
render (h) {
let contents = [
const contents = [
h(
'span',
{
@@ -222,27 +210,27 @@ export default {
)
]
let { expand, collapse, toggle } = this
let scope = {
const { expand, collapse, toggle } = this
const scope = {
expand,
collapse,
toggle,
clamped: this.isClamped,
expanded: this.localExpanded
}
let before = this.$scopedSlots.before
const before = this.$scopedSlots.before
? this.$scopedSlots.before(scope)
: this.$slots.before
if (before) {
contents.unshift(...(Array.isArray(before) ? before : [before]))
}
let after = this.$scopedSlots.after
const after = this.$scopedSlots.after
? this.$scopedSlots.after(scope)
: this.$slots.after
if (after) {
contents.push(...(Array.isArray(after) ? after : [after]))
}
let lines = [
const lines = [
h(
'span',
{