1、添加数学公式渲染功能;2、增加数学公式渲染自定义指令(只适用h5);3、修改package.json
parent
32ddbd1316
commit
9d073a9d06
@ -0,0 +1,6 @@
|
|||||||
|
import mathJax from './mathJax'
|
||||||
|
|
||||||
|
export default function registerDirectives (app) {
|
||||||
|
// 注册全局指令
|
||||||
|
app.directive(mathJax.name, mathJax.inserted)
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
// 该指令只支持H5
|
||||||
|
import renderMath from '@/utils/mathJax/renderMath.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'math',
|
||||||
|
inserted (el, binding) {
|
||||||
|
if (!binding.value) return;
|
||||||
|
// console.log(binding.value)
|
||||||
|
// console.log(Reflect.ownKeys(el.__vnode.el))
|
||||||
|
// console.log(el.__vnode)
|
||||||
|
el.__vnode.el.innerHTML = renderMath(binding.value)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
declare namespace UniCrazyGlobalTypes {
|
||||||
|
interface UniCrazyRouterParams {
|
||||||
|
passedParams?: object | null;
|
||||||
|
routeParams?: object | null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace UniApp {
|
||||||
|
interface RedirectToOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||||
|
interface ReLaunchOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||||
|
interface SwitchTabOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||||
|
interface NavigateBackOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||||
|
interface NavigateToOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/// <reference path="./global.d.ts" />
|
||||||
|
type to = {
|
||||||
|
url: string;
|
||||||
|
query?: object | null;
|
||||||
|
jumpType: string;
|
||||||
|
search?: string;
|
||||||
|
} & UniCrazyGlobalTypes.UniCrazyRouterParams;
|
||||||
|
type from = ({
|
||||||
|
url: string;
|
||||||
|
query?: object | null;
|
||||||
|
search?: string;
|
||||||
|
} & UniCrazyGlobalTypes.UniCrazyRouterParams) | null | undefined;
|
||||||
|
interface callWithNext {
|
||||||
|
(hook: (to: to, from: from, next: Function) => void) : Function;
|
||||||
|
}
|
||||||
|
interface callWithoutNext {
|
||||||
|
(hook: (to: to, from: from) => void): Function;
|
||||||
|
}
|
||||||
|
interface normalCall {
|
||||||
|
(call: Function): void;
|
||||||
|
}
|
||||||
|
export const beforeEach: callWithNext;
|
||||||
|
export const afterEach: callWithoutNext;
|
||||||
|
export const onError: callWithoutNext;
|
||||||
|
export const afterNotNext: normalCall;
|
||||||
|
interface uniCrazyRouter {
|
||||||
|
beforeEach: callWithNext;
|
||||||
|
afterEach: callWithoutNext;
|
||||||
|
onError: callWithoutNext;
|
||||||
|
afterNotNext: normalCall;
|
||||||
|
install: any;
|
||||||
|
}
|
||||||
|
declare const uniCrazyRouter: uniCrazyRouter;
|
||||||
|
export default uniCrazyRouter;
|
||||||
|
// for Vue2
|
||||||
|
declare module "vue/types/vue" {
|
||||||
|
interface Vue {
|
||||||
|
$routeParams?: object | null;
|
||||||
|
$passedParams?: object | null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for Vue3
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
$routeParams?: object | null;
|
||||||
|
$passedParams?: object | null;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,49 @@
|
|||||||
|
/// <reference path="./global.d.ts" />
|
||||||
|
type to = {
|
||||||
|
url: string;
|
||||||
|
query?: object | null;
|
||||||
|
jumpType: string;
|
||||||
|
search?: string;
|
||||||
|
} & UniCrazyGlobalTypes.UniCrazyRouterParams;
|
||||||
|
type from = ({
|
||||||
|
url: string;
|
||||||
|
query?: object | null;
|
||||||
|
search?: string;
|
||||||
|
} & UniCrazyGlobalTypes.UniCrazyRouterParams) | null | undefined;
|
||||||
|
interface callWithNext {
|
||||||
|
(hook: (to: to, from: from, next: Function) => void) : Function;
|
||||||
|
}
|
||||||
|
interface callWithoutNext {
|
||||||
|
(hook: (to: to, from: from) => void): Function;
|
||||||
|
}
|
||||||
|
interface normalCall {
|
||||||
|
(call: Function): void;
|
||||||
|
}
|
||||||
|
export const beforeEach: callWithNext;
|
||||||
|
export const afterEach: callWithoutNext;
|
||||||
|
export const onError: callWithoutNext;
|
||||||
|
export const afterNotNext: normalCall;
|
||||||
|
interface uniCrazyRouter {
|
||||||
|
beforeEach: callWithNext;
|
||||||
|
afterEach: callWithoutNext;
|
||||||
|
onError: callWithoutNext;
|
||||||
|
afterNotNext: normalCall;
|
||||||
|
install: any;
|
||||||
|
}
|
||||||
|
declare const uniCrazyRouter: uniCrazyRouter;
|
||||||
|
export default uniCrazyRouter;
|
||||||
|
// for Vue2
|
||||||
|
declare module "vue/types/vue" {
|
||||||
|
interface Vue {
|
||||||
|
$routeParams?: object | null;
|
||||||
|
$passedParams?: object | null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for Vue3
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
$routeParams?: object | null;
|
||||||
|
$passedParams?: object | null;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@
|
|||||||
|
.search-btn {
|
||||||
|
// margin-top: 15px;
|
||||||
|
// margin-left: 20px;
|
||||||
|
// margin-bottom: 15px;
|
||||||
|
// margin-left: 50%;
|
||||||
|
// transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏canvas
|
||||||
|
uni-canvas {
|
||||||
|
// position: absolute;
|
||||||
|
// top: -1000px;
|
||||||
|
// left: -1000px;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,90 @@
|
|||||||
|
import katex from "katex";
|
||||||
|
import splitAtDelimiters from "./splitAtDelimiters";
|
||||||
|
|
||||||
|
const renderMathInText = function(text, optionsCopy) {
|
||||||
|
const data = splitAtDelimiters(text, optionsCopy.delimiters);
|
||||||
|
if (data.length === 1 && data[0].type === 'text') {
|
||||||
|
// There is no formula in the text.
|
||||||
|
// Let's return null which means there is no need to replace
|
||||||
|
// the current text node with a new one.
|
||||||
|
return data[0].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = ''
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
if (data[i].type === "text") {
|
||||||
|
html += data[i].data;
|
||||||
|
} else {
|
||||||
|
let math = data[i].data;
|
||||||
|
// Override any display mode defined in the settings with that
|
||||||
|
// defined by the text itself
|
||||||
|
optionsCopy.displayMode = data[i].display;
|
||||||
|
try {
|
||||||
|
if (optionsCopy.preProcess) {
|
||||||
|
math = optionsCopy.preProcess(math);
|
||||||
|
}
|
||||||
|
html += katex.renderToString(math, optionsCopy);
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof katex.ParseError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
optionsCopy.errorCallback(
|
||||||
|
"KaTeX auto-render: Failed to parse `" + data[i].data +
|
||||||
|
"` with ",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
html += data[i].rawData;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderMath = function(text, options) {
|
||||||
|
if (!text) {
|
||||||
|
throw new Error("No text provided to render");
|
||||||
|
}
|
||||||
|
|
||||||
|
const optionsCopy = {};
|
||||||
|
|
||||||
|
// Object.assign(optionsCopy, option)
|
||||||
|
for (const option in options) {
|
||||||
|
if (options.hasOwnProperty(option)) {
|
||||||
|
optionsCopy[option] = options[option];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default options
|
||||||
|
optionsCopy.delimiters = optionsCopy.delimiters || [
|
||||||
|
{left: "$$", right: "$$", display: true},
|
||||||
|
{left: "\\(", right: "\\)", display: false},
|
||||||
|
// LaTeX uses $…$, but it ruins the display of normal `$` in text:
|
||||||
|
{left: "$", right: "$", display: false},
|
||||||
|
// $ must come after $$
|
||||||
|
|
||||||
|
// Render AMS environments even if outside $$…$$ delimiters.
|
||||||
|
{left: "\\begin{equation}", right: "\\end{equation}", display: true},
|
||||||
|
{left: "\\begin{align}", right: "\\end{align}", display: true},
|
||||||
|
{left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
|
||||||
|
{left: "\\begin{gather}", right: "\\end{gather}", display: true},
|
||||||
|
{left: "\\begin{CD}", right: "\\end{CD}", display: true},
|
||||||
|
|
||||||
|
{left: "\\[", right: "\\]", display: true},
|
||||||
|
];
|
||||||
|
optionsCopy.ignoredTags = optionsCopy.ignoredTags || [
|
||||||
|
"script", "noscript", "style", "textarea", "pre", "code", "option",
|
||||||
|
];
|
||||||
|
optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || [];
|
||||||
|
optionsCopy.errorCallback = optionsCopy.errorCallback || console.error;
|
||||||
|
|
||||||
|
// Enable sharing of global macros defined via `\gdef` between different
|
||||||
|
// math elements within a single call to `renderMathInElement`.
|
||||||
|
optionsCopy.macros = optionsCopy.macros || {};
|
||||||
|
|
||||||
|
return renderMathInText(text, optionsCopy);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default renderMath;
|
@ -0,0 +1,85 @@
|
|||||||
|
/* eslint no-constant-condition:0 */
|
||||||
|
const findEndOfMath = function(delimiter, text, startIndex) {
|
||||||
|
// Adapted from
|
||||||
|
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
|
||||||
|
let index = startIndex;
|
||||||
|
let braceLevel = 0;
|
||||||
|
|
||||||
|
const delimLength = delimiter.length;
|
||||||
|
|
||||||
|
while (index < text.length) {
|
||||||
|
const character = text[index];
|
||||||
|
|
||||||
|
if (braceLevel <= 0 &&
|
||||||
|
text.slice(index, index + delimLength) === delimiter) {
|
||||||
|
return index;
|
||||||
|
} else if (character === "\\") {
|
||||||
|
index++;
|
||||||
|
} else if (character === "{") {
|
||||||
|
braceLevel++;
|
||||||
|
} else if (character === "}") {
|
||||||
|
braceLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const escapeRegex = function(string) {
|
||||||
|
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||||
|
};
|
||||||
|
|
||||||
|
const amsRegex = /^\\begin{/;
|
||||||
|
|
||||||
|
const splitAtDelimiters = function(text, delimiters) {
|
||||||
|
let index;
|
||||||
|
const data = [];
|
||||||
|
|
||||||
|
const regexLeft = new RegExp(
|
||||||
|
"(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
|
||||||
|
);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
index = text.search(regexLeft);
|
||||||
|
if (index === -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (index > 0) {
|
||||||
|
data.push({
|
||||||
|
type: "text",
|
||||||
|
data: text.slice(0, index),
|
||||||
|
});
|
||||||
|
text = text.slice(index); // now text starts with delimiter
|
||||||
|
}
|
||||||
|
// ... so this always succeeds:
|
||||||
|
const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
|
||||||
|
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
|
||||||
|
if (index === -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const rawData = text.slice(0, index + delimiters[i].right.length);
|
||||||
|
const math = amsRegex.test(rawData)
|
||||||
|
? rawData
|
||||||
|
: text.slice(delimiters[i].left.length, index);
|
||||||
|
data.push({
|
||||||
|
type: "math",
|
||||||
|
data: math,
|
||||||
|
rawData,
|
||||||
|
display: delimiters[i].display,
|
||||||
|
});
|
||||||
|
text = text.slice(index + delimiters[i].right.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text !== "") {
|
||||||
|
data.push({
|
||||||
|
type: "text",
|
||||||
|
data: text,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default splitAtDelimiters;
|
@ -0,0 +1,9 @@
|
|||||||
|
export function createScript(src) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = src;
|
||||||
|
script.onload = () => resolve(script);
|
||||||
|
script.onerror = () => reject(new Error(`Script load error for ${src}`));
|
||||||
|
document.head.append(script);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue