vue-clamp
vue-clamp copied to clipboard
Support for Vue 3.0
Is there any plan to support for vue 3.0?
Any news on this?
Anyone can help?
?
@pangaunn @voratham can you help ?
@b5710546232
Try to use this as VueClamp.vue component file
<script>
import { addListener, removeListener } from "resize-detector";
import { defineComponent } from "vue";
import { h } from "vue";
export default defineComponent({
name: "vue-clamp",
props: {
tag: {
type: String,
default: "div",
},
autoresize: {
type: Boolean,
default: false,
},
maxLines: Number,
maxHeight: [String, Number],
ellipsis: {
type: String,
default: "…",
},
location: {
type: String,
default: "end",
validator(value) {
return ["start", "middle", "end"].indexOf(value) !== -1;
},
},
expanded: Boolean,
},
data() {
return {
offset: null,
text: this.getText(),
localExpanded: !!this.expanded,
};
},
computed: {
clampedText() {
if (this.location === "start") {
return this.ellipsis + (this.text.slice(0, this.offset) || "").trim();
} else if (this.location === "middle") {
const split = Math.floor(this.offset / 2);
return (
(this.text.slice(0, split) || "").trim() +
this.ellipsis +
(this.text.slice(-split) || "").trim()
);
}
return (this.text.slice(0, this.offset) || "").trim() + this.ellipsis;
},
isClamped() {
if (!this.text) {
return false;
}
return this.offset !== this.text.length;
},
realText() {
return this.isClamped ? this.clampedText : this.text;
},
realMaxHeight() {
if (this.localExpanded) {
return null;
}
const { maxHeight } = this;
if (!maxHeight) {
return null;
}
return typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
},
},
watch: {
expanded(val) {
this.localExpanded = val;
},
localExpanded(val) {
if (val) {
this.clampAt(this.text.length);
} else {
this.update();
}
if (this.expanded !== val) {
this.$emit("update:expanded", val);
}
},
isClamped: {
handler(val) {
this.$nextTick(() => this.$emit("clampchange", val));
},
immediate: true,
},
},
mounted() {
this.init();
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();
this.applyChange();
},
beforeUnmount() {
this.cleanUp();
},
methods: {
init() {
const contents = this.$slots.default();
if (!contents) {
return;
}
this.offset = this.text.length;
this.cleanUp();
if (this.autoresize) {
addListener(this.$el, this.update);
this.unregisterResizeCallback = () => {
removeListener(this.$el, this.update);
};
}
this.update();
},
update() {
if (this.localExpanded) {
return;
}
this.applyChange();
if (this.isOverflow() || this.isClamped) {
this.search();
}
},
expand() {
this.localExpanded = true;
},
collapse() {
this.localExpanded = false;
},
toggle() {
this.localExpanded = !this.localExpanded;
},
getLines() {
return Object.keys(
Array.prototype.slice
.call(this.$refs.content.getClientRects())
.reduce((prev, { top, bottom }) => {
const key = `${top}/${bottom}`;
if (!prev[key]) {
prev[key] = true;
}
return prev;
}, {})
).length;
},
isOverflow() {
if (!this.maxLines && !this.maxHeight) {
return false;
}
if (this.maxLines) {
if (this.getLines() > this.maxLines) {
return true;
}
}
if (this.maxHeight) {
if (this.$el.scrollHeight > this.$el.offsetHeight) {
return true;
}
}
return false;
},
getText() {
// Look for the first non-empty text node
const [content] = (this.$slots.default() || []).filter(
(node) => !node.tag && !node.isComment
);
return content ? content.children : "";
},
moveEdge(steps) {
this.clampAt(this.offset + steps);
},
clampAt(offset) {
this.offset = offset;
this.applyChange();
},
applyChange() {
this.$refs.text.textContent = this.realText;
},
stepToFit() {
this.fill();
this.clamp();
},
fill() {
while (
(!this.isOverflow() || this.getLines() < 2) &&
this.offset < this.text.length
) {
this.moveEdge(1);
}
},
clamp() {
while (this.isOverflow() && this.getLines() > 1 && this.offset > 0) {
this.moveEdge(-1);
}
},
search(...range) {
const [from = 0, to = this.offset] = range;
if (to - from <= 3) {
this.stepToFit();
return;
}
const target = Math.floor((to + from) / 2);
this.clampAt(target);
if (this.isOverflow()) {
this.search(from, target);
} else {
this.search(target, to);
}
},
cleanUp() {
if (this.unregisterResizeCallback) {
this.unregisterResizeCallback();
}
},
},
render() {
const contents = [
h(
"span",
{
ref: "text",
attrs: {
"aria-label": this.text?.trim(),
},
},
this.realText
),
];
const { expand, collapse, toggle } = this;
const scope = {
expand,
collapse,
toggle,
clamped: this.isClamped,
expanded: this.localExpanded,
};
const before = this.$slots.before
? this.$slots.before(scope)
: this.$slots.before;
if (before) {
contents.unshift(...(Array.isArray(before) ? before : [before]));
}
const after = this.$slots.after
? this.$slots.after(scope)
: this.$slots.after;
if (after) {
contents.push(...(Array.isArray(after) ? after : [after]));
}
const lines = [
h(
"span",
{
style: {
boxShadow: "transparent 0 0",
},
ref: "content",
},
contents
),
];
return h(
this.tag,
{
style: {
maxHeight: this.realMaxHeight,
overflow: "hidden",
},
},
lines
);
},
});
</script>
@eladcandroid Thx for your code since we would like to vue-clamp
on vue3 typescript version for our project with @b5710546232
I have amount of time from weekend for change codebase to vue3 typescript, but i don't know about watch method
value correct way for vue3 ? but i tested everything working correctly
https://gist.github.com/voratham/4f77d49182a82d6ea84fb244fde857e1
@eladcandroid Thx for your code since we would like to
vue-clamp
on vue3 typescript version for our project with @b5710546232 I have amount of time from weekend for change codebase to vue3 typescript, but i don't know aboutwatch method
value correct way for vue3 ? but i tested everything working correctlyhttps://gist.github.com/voratham/4f77d49182a82d6ea84fb244fde857e1
When the text change the clamp has been not updated. So i come back to use the scrip from eladcandroid and it works.
Thank you both,
vue3 version here 👉 https://github.com/sherwinshen/vue3-text-clamp
When can vue3 be supported
vue3 version here 👉 https://github.com/sherwinshen/vue3-text-clamp
Thank you~